xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 3df69ef35230ca2fc1b68c30e14ff1003612822b)
17c478bd9Sstevel@tonic-gate#!/usr/bin/ksh -p
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6daaffb31Sdp# Common Development and Distribution License (the "License").
7daaffb31Sdp# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
229a70fc3bSMark J. Nelson
237c478bd9Sstevel@tonic-gate#
24cac38512Smjnelson# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate# Use is subject to license terms.
267c478bd9Sstevel@tonic-gate#
27cdf0c1d5Smjnelson
28cdf0c1d5Smjnelson#
29daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
30daaffb31Sdp# suitable for doing a code review of source changes via a web page.
31daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
32daaffb31Sdp# type 'webrev -h'.
337c478bd9Sstevel@tonic-gate#
34daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
35daaffb31Sdp# man page.
367c478bd9Sstevel@tonic-gate#
37daaffb31Sdp
387c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
397c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
407c478bd9Sstevel@tonic-gateNEW_COLOR=blue
417c478bd9Sstevel@tonic-gate
42daaffb31SdpHTML='<?xml version="1.0"?>
43daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
44daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
45daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
46daaffb31Sdp
47daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
48daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
49daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
50daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
51daaffb31Sdp
52cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
53cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
54cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
55daaffb31Sdp<!--
56daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
57daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
58daaffb31Sdp   mechanism available in some browsers.
59daaffb31Sdp
60daaffb31Sdp   For example, to have all "removed" information be red instead of
61daaffb31Sdp   brown, set a rule in your userContent.css file like:
62daaffb31Sdp
63daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
64daaffb31Sdp-->
65daaffb31Sdp<style type="text/css" media="screen">
66daaffb31Sdpbody {
67daaffb31Sdp    background-color: #eeeeee;
68daaffb31Sdp}
69daaffb31Sdphr {
70daaffb31Sdp    border: none 0;
71daaffb31Sdp    border-top: 1px solid #aaa;
72daaffb31Sdp    height: 1px;
73daaffb31Sdp}
74daaffb31Sdpdiv.summary {
75daaffb31Sdp    font-size: .8em;
76daaffb31Sdp    border-bottom: 1px solid #aaa;
77daaffb31Sdp    padding-left: 1em;
78daaffb31Sdp    padding-right: 1em;
79daaffb31Sdp}
80daaffb31Sdpdiv.summary h2 {
81daaffb31Sdp    margin-bottom: 0.3em;
82daaffb31Sdp}
83daaffb31Sdpdiv.summary table th {
84daaffb31Sdp    text-align: right;
85daaffb31Sdp    vertical-align: top;
86daaffb31Sdp    white-space: nowrap;
87daaffb31Sdp}
88daaffb31Sdpspan.lineschanged {
89daaffb31Sdp    font-size: 0.7em;
90daaffb31Sdp}
91daaffb31Sdpspan.oldmarker {
92daaffb31Sdp    color: red;
93daaffb31Sdp    font-size: large;
94daaffb31Sdp    font-weight: bold;
95daaffb31Sdp}
96daaffb31Sdpspan.newmarker {
97daaffb31Sdp    color: green;
98daaffb31Sdp    font-size: large;
99daaffb31Sdp    font-weight: bold;
100daaffb31Sdp}
101daaffb31Sdpspan.removed {
102daaffb31Sdp    color: brown;
103daaffb31Sdp}
104daaffb31Sdpspan.changed {
105daaffb31Sdp    color: blue;
106daaffb31Sdp}
107daaffb31Sdpspan.new {
108daaffb31Sdp    color: blue;
109daaffb31Sdp    font-weight: bold;
110daaffb31Sdp}
111cdf0c1d5Smjnelsonspan.chmod {
112cdf0c1d5Smjnelson    font-size: 0.7em;
113cdf0c1d5Smjnelson    color: #db7800;
114cdf0c1d5Smjnelson}
115daaffb31Sdpa.print { font-size: x-small; }
116daaffb31Sdpa:hover { background-color: #ffcc99; }
117daaffb31Sdp</style>
118daaffb31Sdp
119daaffb31Sdp<style type="text/css" media="print">
120daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
121daaffb31Sdpspan.removed { color: #444; font-style: italic }
122daaffb31Sdpspan.changed { font-weight: bold; }
123daaffb31Sdpspan.new { font-weight: bold; }
124daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
125daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
126daaffb31Sdpa.print {display: none}
127daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
128daaffb31Sdp</style>
129daaffb31Sdp'
130daaffb31Sdp
131daaffb31Sdp#
132daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
133daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
134daaffb31Sdp#
135daaffb31SdpUDIFFCSS='
136daaffb31Sdp<style type="text/css" media="screen">
137daaffb31Sdpspan.new {
138daaffb31Sdp    color: blue;
139daaffb31Sdp    font-weight: normal;
140daaffb31Sdp}
141daaffb31Sdp</style>
142daaffb31Sdp'
143daaffb31Sdp
144daaffb31Sdp#
145daaffb31Sdp# input_cmd | html_quote | output_cmd
146daaffb31Sdp# or
147daaffb31Sdp# html_quote filename | output_cmd
1487c478bd9Sstevel@tonic-gate#
1497c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
1507c478bd9Sstevel@tonic-gate#
1517c478bd9Sstevel@tonic-gatehtml_quote()
1527c478bd9Sstevel@tonic-gate{
1537c478bd9Sstevel@tonic-gate	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
1547c478bd9Sstevel@tonic-gate}
1557c478bd9Sstevel@tonic-gate
156daaffb31Sdp#
157daaffb31Sdp# input_cmd | bug2url | output_cmd
158daaffb31Sdp#
159daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
160daaffb31Sdp#
161daaffb31Sdpbug2url()
1627c478bd9Sstevel@tonic-gate{
163daaffb31Sdp	sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
164daaffb31Sdp}
165daaffb31Sdp
1667c478bd9Sstevel@tonic-gate#
167daaffb31Sdp# input_cmd | sac2url | output_cmd
1687c478bd9Sstevel@tonic-gate#
169daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
170daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
171daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
172daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
1737c478bd9Sstevel@tonic-gate#
174daaffb31Sdpsac2url()
175daaffb31Sdp{
176e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
1770a30ef2cSstevel	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\1/\2/\3\">\1 \2/\3</a>|g'
178daaffb31Sdp	else
179daaffb31Sdp	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
180daaffb31Sdp	fi
181daaffb31Sdp}
182daaffb31Sdp
1837c478bd9Sstevel@tonic-gate#
184daaffb31Sdp# strip_unchanged <infile> | output_cmd
1857c478bd9Sstevel@tonic-gate#
186daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
187daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
1887c478bd9Sstevel@tonic-gate#
189daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
190daaffb31Sdp# identical lines are retained before and after the changed lines to
191daaffb31Sdp# provide some context.  The number of these lines is controlled by the
192cdf0c1d5Smjnelson# variable C in the $AWK script below.
193daaffb31Sdp#
194daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
195daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
196daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
197daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
198daaffb31Sdp#
199daaffb31Sdpstrip_unchanged()
200daaffb31Sdp{
201cdf0c1d5Smjnelson	$AWK '
202daaffb31Sdp	BEGIN	{ C = c = 20 }
203cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
204daaffb31Sdp		if (c > C) {
205daaffb31Sdp			c -= C
206daaffb31Sdp			inx = 0
207daaffb31Sdp			if (c > C) {
208cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
209daaffb31Sdp				inx = c % C
210daaffb31Sdp				c = C
211daaffb31Sdp			}
212daaffb31Sdp
213daaffb31Sdp			for (i = 0; i < c; i++)
214daaffb31Sdp				print ln[(inx + i) % C]
215daaffb31Sdp		}
216daaffb31Sdp		c = 0;
217daaffb31Sdp		print
218daaffb31Sdp		next
219daaffb31Sdp	}
220daaffb31Sdp	{	if (c >= C) {
221daaffb31Sdp			ln[c % C] = $0
222daaffb31Sdp			c++;
223daaffb31Sdp			next;
224daaffb31Sdp		}
225daaffb31Sdp		c++;
226daaffb31Sdp		print
227daaffb31Sdp	}
228cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
229daaffb31Sdp
230daaffb31Sdp	' $1
231daaffb31Sdp}
232daaffb31Sdp
233daaffb31Sdp#
234daaffb31Sdp# sdiff_to_html
235daaffb31Sdp#
236daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
237daaffb31Sdp# processes the diff output to present the files as an HTML document with
238daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
239daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
240daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
241daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
242daaffb31Sdp# e.g.
243daaffb31Sdp#
244daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
245daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
246daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
247daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
248daaffb31Sdp#          1234567</a> my bugid' > <file>.html
249daaffb31Sdp#
250daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
251daaffb31Sdp# in the webrev tree.
252daaffb31Sdp#
253daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
254daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
255daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
256daaffb31Sdp# the editing codes, e.g.
2577c478bd9Sstevel@tonic-gate#
2587c478bd9Sstevel@tonic-gate#      8c8
2597c478bd9Sstevel@tonic-gate#      57a61
2607c478bd9Sstevel@tonic-gate#      63c66,76
2617c478bd9Sstevel@tonic-gate#      68,93d80
2627c478bd9Sstevel@tonic-gate#      106d90
2637c478bd9Sstevel@tonic-gate#      108,110d91
2647c478bd9Sstevel@tonic-gate#
265daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
266daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
267daaffb31Sdp#  into something like this:
2687c478bd9Sstevel@tonic-gate#
2697c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
2707c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
271daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
2727c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
2737c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
2747c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
2757c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
2767c478bd9Sstevel@tonic-gate#        :               :
2777c478bd9Sstevel@tonic-gate#
278daaffb31Sdp#  This script is then run on the original source file to generate the
279daaffb31Sdp#  HTML that corresponds to the source file.
2807c478bd9Sstevel@tonic-gate#
281daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
282daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
283daaffb31Sdp#  notice that the changes are color-coded:
2847c478bd9Sstevel@tonic-gate#
2857c478bd9Sstevel@tonic-gate#   black     - unchanged lines
2867c478bd9Sstevel@tonic-gate#   blue      - changed lines
2877c478bd9Sstevel@tonic-gate#   bold blue - new lines
2887c478bd9Sstevel@tonic-gate#   brown     - deleted lines
2897c478bd9Sstevel@tonic-gate#
290daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
291daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
292daaffb31Sdp#  Teamware's filemerge tool.
293daaffb31Sdp#
294daaffb31Sdpsdiff_to_html()
295daaffb31Sdp{
2967c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
2977c478bd9Sstevel@tonic-gate
298daaffb31Sdp	TNAME=$3
299daaffb31Sdp	TPATH=$4
300daaffb31Sdp	COMMENT=$5
301daaffb31Sdp
3027c478bd9Sstevel@tonic-gate	#
3037c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
3047c478bd9Sstevel@tonic-gate	#
305cdf0c1d5Smjnelson	$AWK '
3067c478bd9Sstevel@tonic-gate	BEGIN	{
3077c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
308daaffb31Sdp		printf "function removed() "
309daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
310daaffb31Sdp		printf "function changed() "
311daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
312daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
3137c478bd9Sstevel@tonic-gate}
3147c478bd9Sstevel@tonic-gate	/^</	{next}
3157c478bd9Sstevel@tonic-gate	/^>/	{next}
3167c478bd9Sstevel@tonic-gate	/^---/	{next}
317daaffb31Sdp
3187c478bd9Sstevel@tonic-gate	{
3197c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
3207c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
3217c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
3227c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
3237c478bd9Sstevel@tonic-gate			if (n == 1)
3247c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
3257c478bd9Sstevel@tonic-gate			else
3267c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
3277c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
3287c478bd9Sstevel@tonic-gate			next
3297c478bd9Sstevel@tonic-gate		}
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
3327c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
3337c478bd9Sstevel@tonic-gate		s = r[1];
3347c478bd9Sstevel@tonic-gate		if (n == 1)
3357c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
3367c478bd9Sstevel@tonic-gate		else {
3377c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
3387c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
3397c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
3407c478bd9Sstevel@tonic-gate		}
3417c478bd9Sstevel@tonic-gate		next
3427c478bd9Sstevel@tonic-gate	}
3437c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
3447c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
3457c478bd9Sstevel@tonic-gate		n1 = r[1]
3467c478bd9Sstevel@tonic-gate		n2 = r[2]
3477c478bd9Sstevel@tonic-gate		if (n == 1)
348daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
3497c478bd9Sstevel@tonic-gate		else
350daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
3517c478bd9Sstevel@tonic-gate		next
3527c478bd9Sstevel@tonic-gate	}
3537c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
3547c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
3557c478bd9Sstevel@tonic-gate		n1 = r[1]
3567c478bd9Sstevel@tonic-gate		n2 = r[2]
3577c478bd9Sstevel@tonic-gate		final = n2
3587c478bd9Sstevel@tonic-gate		d1 = 0
3597c478bd9Sstevel@tonic-gate		if (n == 1)
360daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
3617c478bd9Sstevel@tonic-gate		else {
3627c478bd9Sstevel@tonic-gate			d1 = n2 - n1
363daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
3647c478bd9Sstevel@tonic-gate		}
3657c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
3667c478bd9Sstevel@tonic-gate		n1 = r[1]
3677c478bd9Sstevel@tonic-gate		n2 = r[2]
3687c478bd9Sstevel@tonic-gate		if (m > 1) {
3697c478bd9Sstevel@tonic-gate			d2  = n2 - n1
3707c478bd9Sstevel@tonic-gate			if (d2 > d1) {
3717c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
3727c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
3737c478bd9Sstevel@tonic-gate			}
3747c478bd9Sstevel@tonic-gate		}
3757c478bd9Sstevel@tonic-gate		printf "next}\n" ;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate		next
3787c478bd9Sstevel@tonic-gate	}
3797c478bd9Sstevel@tonic-gate	}
3807c478bd9Sstevel@tonic-gate
381daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
382daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate	#
3857c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
3867c478bd9Sstevel@tonic-gate	#
387cdf0c1d5Smjnelson	$AWK '
3887c478bd9Sstevel@tonic-gate	BEGIN	{
3897c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
390daaffb31Sdp		printf "function new() "
391daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
392daaffb31Sdp		printf "function changed() "
393daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
394daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
3957c478bd9Sstevel@tonic-gate	}
396daaffb31Sdp
3977c478bd9Sstevel@tonic-gate	/^</	{next}
3987c478bd9Sstevel@tonic-gate	/^>/	{next}
3997c478bd9Sstevel@tonic-gate	/^---/	{next}
400daaffb31Sdp
4017c478bd9Sstevel@tonic-gate	{
4027c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
4037c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
4047c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
4057c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
4067c478bd9Sstevel@tonic-gate			if (n == 1)
4077c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
4087c478bd9Sstevel@tonic-gate			else
4097c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
4107c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
4117c478bd9Sstevel@tonic-gate			next
4127c478bd9Sstevel@tonic-gate		}
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
4157c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
4167c478bd9Sstevel@tonic-gate		s = r[1];
4177c478bd9Sstevel@tonic-gate		if (n == 1)
4187c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
4197c478bd9Sstevel@tonic-gate		else {
4207c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
4217c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
4227c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
4237c478bd9Sstevel@tonic-gate		}
4247c478bd9Sstevel@tonic-gate		next
4257c478bd9Sstevel@tonic-gate	}
4267c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
4277c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
4287c478bd9Sstevel@tonic-gate		n1 = r[1]
4297c478bd9Sstevel@tonic-gate		n2 = r[2]
4307c478bd9Sstevel@tonic-gate		if (n == 1)
431daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
4327c478bd9Sstevel@tonic-gate		else
433daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
4347c478bd9Sstevel@tonic-gate		next
4357c478bd9Sstevel@tonic-gate	}
4367c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
4377c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
4387c478bd9Sstevel@tonic-gate		n1 = r[1]
4397c478bd9Sstevel@tonic-gate		n2 = r[2]
4407c478bd9Sstevel@tonic-gate		final = n2
4417c478bd9Sstevel@tonic-gate		d2 = 0;
4427c478bd9Sstevel@tonic-gate		if (n == 1) {
4437c478bd9Sstevel@tonic-gate			final = n1
444daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
4457c478bd9Sstevel@tonic-gate		} else {
4467c478bd9Sstevel@tonic-gate			d2 = n2 - n1
447daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
4487c478bd9Sstevel@tonic-gate		}
4497c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
4507c478bd9Sstevel@tonic-gate		n1 = r[1]
4517c478bd9Sstevel@tonic-gate		n2 = r[2]
4527c478bd9Sstevel@tonic-gate		if (m > 1) {
4537c478bd9Sstevel@tonic-gate			d1  = n2 - n1
4547c478bd9Sstevel@tonic-gate			if (d1 > d2) {
4557c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
4567c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
4577c478bd9Sstevel@tonic-gate			}
4587c478bd9Sstevel@tonic-gate		}
4597c478bd9Sstevel@tonic-gate		printf "next}\n" ;
4607c478bd9Sstevel@tonic-gate		next
4617c478bd9Sstevel@tonic-gate	}
4627c478bd9Sstevel@tonic-gate	}
463daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
4647c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
4657c478bd9Sstevel@tonic-gate
466daaffb31Sdp	#
467cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
468daaffb31Sdp	#
469cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
4707c478bd9Sstevel@tonic-gate
471cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
4727c478bd9Sstevel@tonic-gate
473daaffb31Sdp	#
474daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
475daaffb31Sdp	#
476daaffb31Sdp	print "$HTML<head>$STDHEAD"
477cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
478daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
479daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
480daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
481daaffb31Sdp	print "<table><tr valign=\"top\">"
482daaffb31Sdp	print "<td><pre>"
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
4857c478bd9Sstevel@tonic-gate
486daaffb31Sdp	print "</pre></td><td><pre>"
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
4897c478bd9Sstevel@tonic-gate
490daaffb31Sdp	print "</pre></td>"
491daaffb31Sdp	print "</tr></table>"
492daaffb31Sdp	print "</body></html>"
4937c478bd9Sstevel@tonic-gate
494daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
495daaffb31Sdp	    "$COMMENT"
4967c478bd9Sstevel@tonic-gate}
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate
499daaffb31Sdp#
500daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
501daaffb31Sdp#
502daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
503daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
504daaffb31Sdp# and then emit the main frame.  Content is placed into:
505daaffb31Sdp#
506daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
507daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
508daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
509daaffb31Sdp#
510daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
511daaffb31Sdp#
5127c478bd9Sstevel@tonic-gatefunction framed_sdiff
5137c478bd9Sstevel@tonic-gate{
5147c478bd9Sstevel@tonic-gate	typeset TNAME=$1
515daaffb31Sdp	typeset TPATH=$2
516daaffb31Sdp	typeset lhsfile=$3
517daaffb31Sdp	typeset rhsfile=$4
518daaffb31Sdp	typeset comments=$5
5197c478bd9Sstevel@tonic-gate	typeset RTOP
520daaffb31Sdp
5217c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
522daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
523daaffb31Sdp
524daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
525daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
526daaffb31Sdp
527daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
528cac38512Smjnelson	    <script type="text/javascript" src="$RTOP/ancnav.js"></script>
5297c478bd9Sstevel@tonic-gate	    </head>
530daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
531cac38512Smjnelson	    <a name="0"></a>
532cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
533daaffb31Sdp	EOF
534daaffb31Sdp
535daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
536daaffb31Sdp
537daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
538daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
539daaffb31Sdp
540daaffb31Sdp	close='</body></html>'
541daaffb31Sdp
542daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
543daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
544daaffb31Sdp
545daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
546daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
547daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
548daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
549daaffb31Sdp	  <frameset rows="*,60">
550daaffb31Sdp	    <frameset cols="50%,50%">
551cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
552cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
553daaffb31Sdp	    </frameset>
554daaffb31Sdp	  <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
555cac38512Smjnelson	   marginheight="0" name="nav"></frame>
556daaffb31Sdp	  <noframes>
557daaffb31Sdp            <body id="SUNWwebrev">
558daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
5597c478bd9Sstevel@tonic-gate	      and has the feature enabled.
560daaffb31Sdp            </body>
561daaffb31Sdp	  </noframes>
562daaffb31Sdp	  </frameset>
5637c478bd9Sstevel@tonic-gate	</html>
5647c478bd9Sstevel@tonic-gate	EOF
5657c478bd9Sstevel@tonic-gate}
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate
568daaffb31Sdp#
569daaffb31Sdp# fix_postscript
570daaffb31Sdp#
571daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
572daaffb31Sdp# 	- removing all extraneous headers/trailers
573daaffb31Sdp#	- making the page numbers right
574daaffb31Sdp#	- removing pages devoid of contents which confuse some
575daaffb31Sdp#	  postscript readers.
576daaffb31Sdp#
577daaffb31Sdp# From Casper.
578daaffb31Sdp#
579daaffb31Sdpfunction fix_postscript
5807c478bd9Sstevel@tonic-gate{
581daaffb31Sdp	infile=$1
5827c478bd9Sstevel@tonic-gate
583daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
5847c478bd9Sstevel@tonic-gate
585daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
586daaffb31Sdp	print "%%Orientation: Landscape\n";
5877c478bd9Sstevel@tonic-gate
588daaffb31Sdp	$pno = 0;
589daaffb31Sdp	$doprint = 1;
590daaffb31Sdp
591daaffb31Sdp	$page = "";
592daaffb31Sdp
593daaffb31Sdp	while (<>) {
594daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
595daaffb31Sdp
596daaffb31Sdp		if (/^%%Page:/) {
597daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
598daaffb31Sdp				# Header or single page containing text
599daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
600daaffb31Sdp				print $page;
601daaffb31Sdp				$pno++;
602daaffb31Sdp			} else {
603daaffb31Sdp				# Empty page, skip it.
6047c478bd9Sstevel@tonic-gate			}
605daaffb31Sdp			$page = "";
606daaffb31Sdp			$doprint = 1;
6077c478bd9Sstevel@tonic-gate			next;
6087c478bd9Sstevel@tonic-gate		}
6097c478bd9Sstevel@tonic-gate
610daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
611daaffb31Sdp		# %%Page of the next
612daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
613daaffb31Sdp		$page .= $_ if ($doprint);
6147c478bd9Sstevel@tonic-gate	}
6157c478bd9Sstevel@tonic-gate
616daaffb31Sdp	if ($page =~ /\)S/) {
617daaffb31Sdp		print "%%Page: ? $pno\n";
618daaffb31Sdp		print $page;
619daaffb31Sdp	} else {
620daaffb31Sdp		$pno--;
621daaffb31Sdp	}
622daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
623daaffb31SdpEOF
624daaffb31Sdp
62514983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
626daaffb31Sdp}
627daaffb31Sdp
628daaffb31Sdp
629daaffb31Sdp#
630daaffb31Sdp# input_cmd | insert_anchors | output_cmd
631daaffb31Sdp#
6327c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
633daaffb31Sdp# anchors.  These are used to drive the frames version of the
6347c478bd9Sstevel@tonic-gate# sdiffs output.
6357c478bd9Sstevel@tonic-gate#
6367c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
6377c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
6387c478bd9Sstevel@tonic-gate#
639daaffb31Sdp# The script detects changed lines as any line that has a "<span
640daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
641daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
6427c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
6437c478bd9Sstevel@tonic-gate# deleted.
6447c478bd9Sstevel@tonic-gate#
645daaffb31Sdpfunction insert_anchors
646daaffb31Sdp{
647cdf0c1d5Smjnelson	$AWK '
6487c478bd9Sstevel@tonic-gate	function ia() {
649daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
6507c478bd9Sstevel@tonic-gate	}
651daaffb31Sdp
6527c478bd9Sstevel@tonic-gate	BEGIN {
653daaffb31Sdp		anc=1;
6547c478bd9Sstevel@tonic-gate		inblock=1;
655daaffb31Sdp		printf "<pre>\n";
6567c478bd9Sstevel@tonic-gate	}
657daaffb31Sdp	NF == 0 || /^<span class=/ {
6587c478bd9Sstevel@tonic-gate		if (inblock == 0) {
6597c478bd9Sstevel@tonic-gate			ia();
6607c478bd9Sstevel@tonic-gate			inblock=1;
6617c478bd9Sstevel@tonic-gate		}
6627c478bd9Sstevel@tonic-gate		print;
6637c478bd9Sstevel@tonic-gate		next;
6647c478bd9Sstevel@tonic-gate	}
6657c478bd9Sstevel@tonic-gate	{
6667c478bd9Sstevel@tonic-gate		inblock=0;
6677c478bd9Sstevel@tonic-gate		print;
6687c478bd9Sstevel@tonic-gate	}
6697c478bd9Sstevel@tonic-gate	END {
6707c478bd9Sstevel@tonic-gate		ia();
671daaffb31Sdp
672daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
673daaffb31Sdp		printf "--- EOF ---</b>"
6747c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
675daaffb31Sdp		printf "</pre>"
676daaffb31Sdp		printf "<form name=\"eof\">";
677cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
678cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
679daaffb31Sdp		printf "</form>";
6807c478bd9Sstevel@tonic-gate	}
6817c478bd9Sstevel@tonic-gate	' $1
6827c478bd9Sstevel@tonic-gate}
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate
685daaffb31Sdp#
686daaffb31Sdp# relative_dir
687daaffb31Sdp#
688daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
689daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
690daaffb31Sdp# this function would print "../../../../".
691daaffb31Sdp#
692daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
693daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
694daaffb31Sdp# is not relocatable.
695daaffb31Sdp#
696daaffb31Sdpfunction relative_dir
6977c478bd9Sstevel@tonic-gate{
698daaffb31Sdp	typeset cur="${1##$2?(/)}"
699daaffb31Sdp	typeset ret=""
700daaffb31Sdp	if [[ $2 == $cur ]]; then   # Should never happen.
701daaffb31Sdp		# Should never happen.
70214983201Sdp		print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
703daaffb31Sdp		print -u2 "to \"$2\".  Check input paths.  Framed webrev "
704daaffb31Sdp		print -u2 "will not be relocatable!"
705daaffb31Sdp		print $2
706daaffb31Sdp		return
707daaffb31Sdp	fi
708daaffb31Sdp
709daaffb31Sdp	while [[ -n ${cur} ]];
7107c478bd9Sstevel@tonic-gate	do
7117c478bd9Sstevel@tonic-gate		cur=${cur%%*(/)*([!/])}
712daaffb31Sdp		if [[ -z $ret ]]; then
713daaffb31Sdp			ret=".."
714daaffb31Sdp		else
7157c478bd9Sstevel@tonic-gate			ret="../$ret"
716daaffb31Sdp		fi
7177c478bd9Sstevel@tonic-gate	done
7187c478bd9Sstevel@tonic-gate	print $ret
7197c478bd9Sstevel@tonic-gate}
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate
722daaffb31Sdp#
723daaffb31Sdp# frame_nav_js
724daaffb31Sdp#
725daaffb31Sdp# Emit javascript for frame navigation
726daaffb31Sdp#
727daaffb31Sdpfunction frame_nav_js
7287c478bd9Sstevel@tonic-gate{
7297c478bd9Sstevel@tonic-gatecat << \EOF
7307c478bd9Sstevel@tonic-gatevar myInt;
7317c478bd9Sstevel@tonic-gatevar scrolling=0;
732daaffb31Sdpvar sfactor = 3;
7337c478bd9Sstevel@tonic-gatevar scount=10;
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gatefunction scrollByPix() {
7367c478bd9Sstevel@tonic-gate	if (scount<=0) {
7377c478bd9Sstevel@tonic-gate		sfactor*=1.2;
7387c478bd9Sstevel@tonic-gate		scount=10;
7397c478bd9Sstevel@tonic-gate	}
7407c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
7417c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
7427c478bd9Sstevel@tonic-gate	scount--;
7437c478bd9Sstevel@tonic-gate}
7447c478bd9Sstevel@tonic-gate
745daaffb31Sdpfunction scrollToAnc(num) {
746daaffb31Sdp
747daaffb31Sdp	// Update the value of the anchor in the form which we use as
748daaffb31Sdp	// storage for this value.  setAncValue() will take care of
749daaffb31Sdp	// correcting for overflow and underflow of the value and return
750daaffb31Sdp	// us the new value.
751daaffb31Sdp	num = setAncValue(num);
752daaffb31Sdp
753daaffb31Sdp	// Set location and scroll back a little to expose previous
754daaffb31Sdp	// lines.
755daaffb31Sdp	//
756daaffb31Sdp	// Note that this could be improved: it is possible although
757daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
758daaffb31Sdp	// scroll to that location directly.
759daaffb31Sdp	//
7607c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
7617c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
762daaffb31Sdp
7637c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
7647c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
7657c478bd9Sstevel@tonic-gate}
7667c478bd9Sstevel@tonic-gate
767daaffb31Sdpfunction getAncValue()
768daaffb31Sdp{
769daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
770daaffb31Sdp}
771daaffb31Sdp
772daaffb31Sdpfunction setAncValue(val)
773daaffb31Sdp{
774daaffb31Sdp	if (val <= 0) {
775daaffb31Sdp		val = 0;
776daaffb31Sdp		parent.nav.document.diff.real.value = val;
777daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
778daaffb31Sdp		return (val);
779daaffb31Sdp	}
780daaffb31Sdp
781daaffb31Sdp	//
782daaffb31Sdp	// The way we compute the max anchor value is to stash it
783daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
784daaffb31Sdp	// on each side, so we pluck from the left.
785daaffb31Sdp	//
786daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
787daaffb31Sdp	if (val < maxval) {
788daaffb31Sdp		parent.nav.document.diff.real.value = val;
789daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
790daaffb31Sdp		return (val);
791daaffb31Sdp	}
792daaffb31Sdp
793daaffb31Sdp	// this must be: val >= maxval
794daaffb31Sdp	val = maxval;
795daaffb31Sdp	parent.nav.document.diff.real.value = val;
796daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
797daaffb31Sdp	return (val);
798daaffb31Sdp}
799daaffb31Sdp
8007c478bd9Sstevel@tonic-gatefunction stopScroll() {
8017c478bd9Sstevel@tonic-gate	if (scrolling==1) {
8027c478bd9Sstevel@tonic-gate		clearInterval(myInt);
8037c478bd9Sstevel@tonic-gate		scrolling=0;
8047c478bd9Sstevel@tonic-gate	}
8057c478bd9Sstevel@tonic-gate}
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gatefunction startScroll() {
8087c478bd9Sstevel@tonic-gate	stopScroll();
8097c478bd9Sstevel@tonic-gate	scrolling=1;
8107c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
8117c478bd9Sstevel@tonic-gate}
8127c478bd9Sstevel@tonic-gate
8137c478bd9Sstevel@tonic-gatefunction handlePress(b) {
814daaffb31Sdp
8157c478bd9Sstevel@tonic-gate	switch (b) {
8167c478bd9Sstevel@tonic-gate	    case 1 :
817daaffb31Sdp		scrollToAnc(-1);
8187c478bd9Sstevel@tonic-gate		break;
8197c478bd9Sstevel@tonic-gate	    case 2 :
820daaffb31Sdp		scrollToAnc(getAncValue() - 1);
8217c478bd9Sstevel@tonic-gate		break;
8227c478bd9Sstevel@tonic-gate	    case 3 :
8237c478bd9Sstevel@tonic-gate		sfactor=-3;
8247c478bd9Sstevel@tonic-gate		startScroll();
8257c478bd9Sstevel@tonic-gate		break;
8267c478bd9Sstevel@tonic-gate	    case 4 :
8277c478bd9Sstevel@tonic-gate		sfactor=3;
8287c478bd9Sstevel@tonic-gate		startScroll();
8297c478bd9Sstevel@tonic-gate		break;
8307c478bd9Sstevel@tonic-gate	    case 5 :
831daaffb31Sdp		scrollToAnc(getAncValue() + 1);
8327c478bd9Sstevel@tonic-gate		break;
8337c478bd9Sstevel@tonic-gate	    case 6 :
834daaffb31Sdp		scrollToAnc(999999);
8357c478bd9Sstevel@tonic-gate		break;
8367c478bd9Sstevel@tonic-gate	}
8377c478bd9Sstevel@tonic-gate}
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
8407c478bd9Sstevel@tonic-gate	stopScroll();
8417c478bd9Sstevel@tonic-gate}
8427c478bd9Sstevel@tonic-gate
843daaffb31Sdpfunction keypress(ev) {
844daaffb31Sdp	var keynum;
845daaffb31Sdp	var keychar;
846daaffb31Sdp
847daaffb31Sdp	if (window.event) { // IE
848daaffb31Sdp		keynum = ev.keyCode;
849daaffb31Sdp	} else if (ev.which) { // non-IE
850daaffb31Sdp		keynum = ev.which;
851daaffb31Sdp	}
852daaffb31Sdp
853daaffb31Sdp	keychar = String.fromCharCode(keynum);
854daaffb31Sdp
855daaffb31Sdp	if (keychar == "k") {
856daaffb31Sdp		handlePress(2);
857daaffb31Sdp		return (0);
858daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
859daaffb31Sdp		handlePress(5);
860daaffb31Sdp		return (0);
861daaffb31Sdp	}
862daaffb31Sdp	return (1);
863daaffb31Sdp}
864daaffb31Sdp
8657c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
866daaffb31Sdp	val = parent.nav.document.diff.display.value;
867daaffb31Sdp	if (val == "EOF") {
868daaffb31Sdp		scrollToAnc(999999);
869daaffb31Sdp		return;
870daaffb31Sdp	}
871daaffb31Sdp
872daaffb31Sdp	if (val == "BOF") {
873daaffb31Sdp		scrollToAnc(0);
874daaffb31Sdp		return;
875daaffb31Sdp	}
876daaffb31Sdp
877daaffb31Sdp        i=parseInt(val);
8787c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
879daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
8807c478bd9Sstevel@tonic-gate        } else {
881daaffb31Sdp                scrollToAnc(i);
8827c478bd9Sstevel@tonic-gate        }
8837c478bd9Sstevel@tonic-gate        return false;
8847c478bd9Sstevel@tonic-gate}
8857c478bd9Sstevel@tonic-gate
886daaffb31SdpEOF
887daaffb31Sdp}
888daaffb31Sdp
889daaffb31Sdp#
890daaffb31Sdp# frame_navigation
891daaffb31Sdp#
892daaffb31Sdp# Output anchor navigation file for framed sdiffs.
893daaffb31Sdp#
894daaffb31Sdpfunction frame_navigation
895daaffb31Sdp{
896daaffb31Sdp	print "$HTML<head>$STDHEAD"
897daaffb31Sdp
898daaffb31Sdp	cat << \EOF
899daaffb31Sdp<title>Anchor Navigation</title>
900daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
901daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
902daaffb31Sdp
903daaffb31Sdp<style type="text/css">
904daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
905daaffb31Sdp		    background-color: #eee; text-align: center;
906daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
907daaffb31Sdp    div.button a { font-weight: bold; color: black }
908daaffb31Sdp    div.button td:hover { background: #ffcc99; }
909daaffb31Sdp</style>
910daaffb31SdpEOF
911daaffb31Sdp
912cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
913daaffb31Sdp
914daaffb31Sdp	cat << \EOF
9157c478bd9Sstevel@tonic-gate</head>
916daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
917daaffb31Sdp	onkeypress="keypress(event);">
9187c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
9197c478bd9Sstevel@tonic-gate      <center>
920cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
9217c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
9227c478bd9Sstevel@tonic-gate      </center>
9237c478bd9Sstevel@tonic-gate    </noscript>
9247c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
925daaffb31Sdp	<tr>
926daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
927daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
928daaffb31Sdp          at right</td>
929daaffb31Sdp	  <td align="center" valign="top" width="50%">
9307c478bd9Sstevel@tonic-gate	    <div class="button">
931daaffb31Sdp	      <table border="0" align="center">
932daaffb31Sdp                  <tr>
933daaffb31Sdp		    <td>
9347c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
9357c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
9367c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
9377c478bd9Sstevel@tonic-gate			 onClick="return false;"
9387c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
939daaffb31Sdp		    <td>
9407c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
9417c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
9427c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
9437c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
944daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
945daaffb31Sdp		    <td>
9467c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
9477c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
9487c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
9497c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
9507c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
9517c478bd9Sstevel@tonic-gate		    </td></tr>
952daaffb31Sdp
9537c478bd9Sstevel@tonic-gate		  <tr>
954daaffb31Sdp		    <td>
9557c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
9567c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
9577c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
9587c478bd9Sstevel@tonic-gate			 onClick="return false;"
9597c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
960daaffb31Sdp		    <td>
9617c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
9627c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
9637c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
9647c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
965daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
966daaffb31Sdp		    <td>
9677c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
9687c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
9697c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
9707c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
9717c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
972daaffb31Sdp		  </tr>
973daaffb31Sdp              </table>
974daaffb31Sdp	    </div>
975daaffb31Sdp	  </td>
9767c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
977daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
978cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
979cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
9807c478bd9Sstevel@tonic-gate	    </form>
9817c478bd9Sstevel@tonic-gate	  </th>
982daaffb31Sdp	</tr>
9837c478bd9Sstevel@tonic-gate    </table>
9847c478bd9Sstevel@tonic-gate  </body>
9857c478bd9Sstevel@tonic-gate</html>
9867c478bd9Sstevel@tonic-gateEOF
9877c478bd9Sstevel@tonic-gate}
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate
990daaffb31Sdp
991daaffb31Sdp#
992daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
993daaffb31Sdp#
994daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
995daaffb31Sdp# context or unified diffs.
996daaffb31Sdp#
9977c478bd9Sstevel@tonic-gatediff_to_html()
9987c478bd9Sstevel@tonic-gate{
9997c478bd9Sstevel@tonic-gate	TNAME=$1
1000daaffb31Sdp	TPATH=$2
1001daaffb31Sdp	DIFFTYPE=$3
1002daaffb31Sdp	COMMENT=$4
1003daaffb31Sdp
1004daaffb31Sdp	print "$HTML<head>$STDHEAD"
1005daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1006daaffb31Sdp
1007daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1008daaffb31Sdp		print "$UDIFFCSS"
1009daaffb31Sdp	fi
1010daaffb31Sdp
1011daaffb31Sdp	cat <<-EOF
1012daaffb31Sdp	</head>
1013daaffb31Sdp	<body id="SUNWwebrev">
1014daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1015daaffb31Sdp	<pre>$COMMENT</pre>
1016daaffb31Sdp        <pre>
1017daaffb31Sdp	EOF
10187c478bd9Sstevel@tonic-gate
1019cdf0c1d5Smjnelson	html_quote | $AWK '
1020daaffb31Sdp	/^--- new/	{ next }
1021daaffb31Sdp	/^\+\+\+ new/	{ next }
1022daaffb31Sdp	/^--- old/	{ next }
1023daaffb31Sdp	/^\*\*\* old/	{ next }
1024daaffb31Sdp	/^\*\*\*\*/	{ next }
10257c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1026cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1027daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1028daaffb31Sdp			  next}
1029daaffb31Sdp
1030cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1031daaffb31Sdp			  next}
1032daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1033daaffb31Sdp			  next}
1034daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1035daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1036daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1037daaffb31Sdp			{printf "%s\n", $0; next}
10387c478bd9Sstevel@tonic-gate	'
1039daaffb31Sdp
1040daaffb31Sdp	print "</pre></body></html>\n"
10417c478bd9Sstevel@tonic-gate}
10427c478bd9Sstevel@tonic-gate
10437c478bd9Sstevel@tonic-gate
1044daaffb31Sdp#
1045daaffb31Sdp# source_to_html { new | old } <filename>
1046daaffb31Sdp#
1047daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1048daaffb31Sdp#
10497c478bd9Sstevel@tonic-gatesource_to_html()
10507c478bd9Sstevel@tonic-gate{
10517c478bd9Sstevel@tonic-gate	WHICH=$1
10527c478bd9Sstevel@tonic-gate	TNAME=$2
10537c478bd9Sstevel@tonic-gate
1054daaffb31Sdp	print "$HTML<head>$STDHEAD"
1055cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1056daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1057daaffb31Sdp	print "<pre>"
1058cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1059daaffb31Sdp	print "</pre></body></html>"
10607c478bd9Sstevel@tonic-gate}
10617c478bd9Sstevel@tonic-gate
1062daaffb31Sdp#
1063cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1064daaffb31Sdp#
1065daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1066daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1067daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1068daaffb31Sdp# delta in that list (the first delta unique to the child).
10697c478bd9Sstevel@tonic-gate#
10707c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1071daaffb31Sdp#
1072daaffb31Sdpcomments_from_teamware()
10737c478bd9Sstevel@tonic-gate{
1074daaffb31Sdp	fmt=$1
1075daaffb31Sdp	pfile=$PWS/$2
1076daaffb31Sdp	cfile=$CWS/$3
10777c478bd9Sstevel@tonic-gate
1078cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1079cdf0c1d5Smjnelson		pfile=$RWS/$2
1080cdf0c1d5Smjnelson	fi
1081cdf0c1d5Smjnelson
1082daaffb31Sdp	if [[ -f $pfile ]]; then
1083cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
10847c478bd9Sstevel@tonic-gate	else
10857c478bd9Sstevel@tonic-gate		psid=1.1
10867c478bd9Sstevel@tonic-gate	fi
10877c478bd9Sstevel@tonic-gate
1088cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
10897c478bd9Sstevel@tonic-gate	N=${#sids[@]}
10907c478bd9Sstevel@tonic-gate
1091daaffb31Sdp	nawkprg='
1092daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1093daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1094daaffb31Sdp		NF == 0u	{ continue }
1095daaffb31Sdp		{if (p==0) continue; print $0 }'
1096daaffb31Sdp
10977c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
10987c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
10997c478bd9Sstevel@tonic-gate
1100daaffb31Sdp		if [[ $fmt == "text" ]]; then
1101cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1102cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1103daaffb31Sdp			return
1104daaffb31Sdp		fi
1105daaffb31Sdp
1106cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1107cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
11087c478bd9Sstevel@tonic-gate	fi
11097c478bd9Sstevel@tonic-gate}
11107c478bd9Sstevel@tonic-gate
1111daaffb31Sdp#
1112cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1113daaffb31Sdp#
1114cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1115cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1116cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1117cdf0c1d5Smjnelson# are turned into URLs.
1118cdf0c1d5Smjnelson#
1119cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1120daaffb31Sdp#
1121daaffb31Sdpcomments_from_wx()
11227c478bd9Sstevel@tonic-gate{
1123daaffb31Sdp	typeset fmt=$1
1124daaffb31Sdp	typeset p=$2
11257c478bd9Sstevel@tonic-gate
1126cdf0c1d5Smjnelson	comm=`$AWK '
1127daaffb31Sdp	$1 == "'$p'" {
11287c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
11297c478bd9Sstevel@tonic-gate		getline
11307c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
11317c478bd9Sstevel@tonic-gate		exit
1132daaffb31Sdp	}' < $wxfile`
1133daaffb31Sdp
1134cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1135cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1136cdf0c1d5Smjnelson	fi
1137cdf0c1d5Smjnelson
1138daaffb31Sdp	if [[ $fmt == "text" ]]; then
1139cdf0c1d5Smjnelson		print -- "$comm"
1140daaffb31Sdp		return
1141daaffb31Sdp	fi
1142daaffb31Sdp
1143cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1144cdf0c1d5Smjnelson
11457c478bd9Sstevel@tonic-gate}
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate#
1148daaffb31Sdp# getcomments {text|html} filepath parentpath
1149daaffb31Sdp#
1150daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1151daaffb31Sdp#
1152daaffb31Sdpgetcomments()
1153daaffb31Sdp{
1154daaffb31Sdp	typeset fmt=$1
1155daaffb31Sdp	typeset p=$2
1156daaffb31Sdp	typeset pp=$3
11577c478bd9Sstevel@tonic-gate
1158*3df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
1159*3df69ef3SDarren Moffat		return
1160*3df69ef3SDarren Moffat	fi
1161cdf0c1d5Smjnelson	#
1162cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1163cdf0c1d5Smjnelson	# will be used there, too
1164cdf0c1d5Smjnelson	#
1165daaffb31Sdp	if [[ -n $wxfile ]]; then
1166daaffb31Sdp		comments_from_wx $fmt $p
1167daaffb31Sdp	else
1168daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1169daaffb31Sdp			comments_from_teamware $fmt $pp $p
1170daaffb31Sdp		fi
1171daaffb31Sdp	fi
1172daaffb31Sdp}
1173daaffb31Sdp
1174daaffb31Sdp#
1175daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1176daaffb31Sdp#
1177daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1178daaffb31Sdp#
1179daaffb31Sdpfunction printCI
1180daaffb31Sdp{
1181daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1182daaffb31Sdp	typeset str
1183daaffb31Sdp	if (( tot == 1 )); then
1184daaffb31Sdp		str="line"
1185daaffb31Sdp	else
1186daaffb31Sdp		str="lines"
1187daaffb31Sdp	fi
1188daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1189daaffb31Sdp	    $tot $str $ins $del $mod $unc
1190daaffb31Sdp}
1191daaffb31Sdp
1192daaffb31Sdp
1193daaffb31Sdp#
1194daaffb31Sdp# difflines <oldfile> <newfile>
1195daaffb31Sdp#
1196daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1197daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1198daaffb31Sdp#
11997c478bd9Sstevel@tonic-gatefunction difflines
12007c478bd9Sstevel@tonic-gate{
1201daaffb31Sdp	integer tot mod del ins unc err
12027c478bd9Sstevel@tonic-gate	typeset filename
12037c478bd9Sstevel@tonic-gate
1204cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1205daaffb31Sdp	# Change range of lines: N,Nc
12067c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
12077c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
12087c478bd9Sstevel@tonic-gate		if (n != 2) {
12097c478bd9Sstevel@tonic-gate		    error=2
12107c478bd9Sstevel@tonic-gate		    exit;
12117c478bd9Sstevel@tonic-gate		}
1212daaffb31Sdp		#
1213daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1214daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1215daaffb31Sdp		#
12167c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1217daaffb31Sdp
1218daaffb31Sdp		#
1219daaffb31Sdp		# Now count replacement lines: each represents a change instead
1220daaffb31Sdp		# of a delete, so increment c and decrement r.
1221daaffb31Sdp		#
12227c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
12237c478bd9Sstevel@tonic-gate			c++;
12247c478bd9Sstevel@tonic-gate			r--;
12257c478bd9Sstevel@tonic-gate		}
1226daaffb31Sdp		#
1227daaffb31Sdp		# If there were more replacement lines than original lines,
1228daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1229daaffb31Sdp		# but there are r changes that should be counted as adds, and
1230daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1231daaffb31Sdp		#
12327c478bd9Sstevel@tonic-gate		if (r < 0) {
12337c478bd9Sstevel@tonic-gate			a-=r;
12347c478bd9Sstevel@tonic-gate			c+=r;
12357c478bd9Sstevel@tonic-gate		}
1236daaffb31Sdp
1237daaffb31Sdp		#
1238daaffb31Sdp		# If there were more original lines than replacement lines, then
1239daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1240daaffb31Sdp		#
12417c478bd9Sstevel@tonic-gate		if (r > 0) {
12427c478bd9Sstevel@tonic-gate			d+=r;
12437c478bd9Sstevel@tonic-gate		}
12447c478bd9Sstevel@tonic-gate		next;
12457c478bd9Sstevel@tonic-gate	}
12467c478bd9Sstevel@tonic-gate
1247daaffb31Sdp	# Change lines: Nc
12487c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1249daaffb31Sdp		# The first line is a replacement; any more are additions.
12507c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
12517c478bd9Sstevel@tonic-gate			c++;
12527c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
12537c478bd9Sstevel@tonic-gate		}
12547c478bd9Sstevel@tonic-gate		next;
12557c478bd9Sstevel@tonic-gate	}
12567c478bd9Sstevel@tonic-gate
1257daaffb31Sdp	# Add lines: both Na and N,Na
12587c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
12597c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
12607c478bd9Sstevel@tonic-gate		next;
12617c478bd9Sstevel@tonic-gate	}
12627c478bd9Sstevel@tonic-gate
1263daaffb31Sdp	# Delete range of lines: N,Nd
12647c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
12657c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
12667c478bd9Sstevel@tonic-gate		if (n != 2) {
12677c478bd9Sstevel@tonic-gate			error=2
12687c478bd9Sstevel@tonic-gate			exit;
12697c478bd9Sstevel@tonic-gate		}
1270daaffb31Sdp		#
1271daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1272daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1273daaffb31Sdp		#
12747c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
12757c478bd9Sstevel@tonic-gate		d+=r;
12767c478bd9Sstevel@tonic-gate		next;
12777c478bd9Sstevel@tonic-gate	}
12787c478bd9Sstevel@tonic-gate
1279daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
12807c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
12817c478bd9Sstevel@tonic-gate
1282daaffb31Sdp	# Should not get here!
12837c478bd9Sstevel@tonic-gate	{
12847c478bd9Sstevel@tonic-gate		error=1;
12857c478bd9Sstevel@tonic-gate		exit;
12867c478bd9Sstevel@tonic-gate	}
12877c478bd9Sstevel@tonic-gate
1288daaffb31Sdp	# Finish off - print results
12897c478bd9Sstevel@tonic-gate	END {
1290daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
12917c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
12927c478bd9Sstevel@tonic-gate	}' )
12937c478bd9Sstevel@tonic-gate
1294cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
12957c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1296daaffb31Sdp		print "Unexpected Error occurred reading" \
1297daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1298daaffb31Sdp		return
1299daaffb31Sdp	fi
1300daaffb31Sdp
13017c478bd9Sstevel@tonic-gate	# Accumulate totals
13027c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1303daaffb31Sdp	(( TMOD += mod ))
13047c478bd9Sstevel@tonic-gate	(( TDEL += del ))
13057c478bd9Sstevel@tonic-gate	(( TINS += ins ))
13067c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1307cdf0c1d5Smjnelson	unc=`wc -l < $1`
13087c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1309daaffb31Sdp		(( unc -= del + mod ))
13107c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
13117c478bd9Sstevel@tonic-gate	fi
13127c478bd9Sstevel@tonic-gate	# print summary
1313daaffb31Sdp	print "<span class=\"lineschanged\">"
1314daaffb31Sdp	printCI $tot $ins $del $mod $unc
1315daaffb31Sdp	print "</span>"
13167c478bd9Sstevel@tonic-gate}
13177c478bd9Sstevel@tonic-gate
1318daaffb31Sdp
13197c478bd9Sstevel@tonic-gate#
1320daaffb31Sdp# flist_from_wx
1321daaffb31Sdp#
1322daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1323daaffb31Sdp# Sets the global 'wxfile' variable.
1324daaffb31Sdp#
1325daaffb31Sdpfunction flist_from_wx
13267c478bd9Sstevel@tonic-gate{
1327daaffb31Sdp	typeset argfile=$1
1328daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1329daaffb31Sdp		#
1330daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1331daaffb31Sdp		# because the webrev does a "cd" later on.
1332daaffb31Sdp		#
1333daaffb31Sdp		wxfile=$PWD/$argfile
13347c478bd9Sstevel@tonic-gate	else
1335daaffb31Sdp		wxfile=$argfile
13367c478bd9Sstevel@tonic-gate	fi
13377c478bd9Sstevel@tonic-gate
1338cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
13397c478bd9Sstevel@tonic-gate	  while (getline) {
13407c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
13417c478bd9Sstevel@tonic-gate		if (c > 0) print
13427c478bd9Sstevel@tonic-gate	  }
1343daaffb31Sdp	}' $wxfile > $FLIST
13447c478bd9Sstevel@tonic-gate
1345daaffb31Sdp	print " Done."
1346daaffb31Sdp}
13477c478bd9Sstevel@tonic-gate
1348daaffb31Sdp#
1349daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1350daaffb31Sdp#
1351daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1352daaffb31Sdp# names may come from the "update/create" messages and others from the
1353daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1354daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1355daaffb31Sdp# -n as well, but remove them if they are already defined.
1356daaffb31Sdp#
1357daaffb31Sdpfunction flist_from_teamware
1358daaffb31Sdp{
1359cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1360daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1361daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1362daaffb31Sdp			    "valid teamware workspace"
13637c478bd9Sstevel@tonic-gate			exit 1
13647c478bd9Sstevel@tonic-gate		fi
1365daaffb31Sdp		parent_args="-p $codemgr_parent"
13667c478bd9Sstevel@tonic-gate	fi
13677c478bd9Sstevel@tonic-gate
1368daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
13697c478bd9Sstevel@tonic-gate
1370daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1371cdf0c1d5Smjnelson	    $AWK '
1372daaffb31Sdp		/^update:|^create:/	{print $2}
1373daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1374daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1375daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1376daaffb31Sdp		NF == 0			{p=0 ; continue}
1377daaffb31Sdp		/^rename/		{old=$3}
1378daaffb31Sdp		$1 == "to:"		{print $2, old}
1379daaffb31Sdp		/^"/			{continue}
1380daaffb31Sdp		p == 1			{print $1}' |
1381daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
13827c478bd9Sstevel@tonic-gate
1383daaffb31Sdp	print " Done."
1384daaffb31Sdp}
1385daaffb31Sdp
1386cdf0c1d5Smjnelson#
1387cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1388cdf0c1d5Smjnelson#
1389cdf0c1d5Smjnelsonfunction hg_active_wxfile
1390cdf0c1d5Smjnelson{
1391cdf0c1d5Smjnelson	typeset child=$1
1392cdf0c1d5Smjnelson	typeset parent=$2
1393cdf0c1d5Smjnelson
1394cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
13959a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1396cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1397cdf0c1d5Smjnelson}
1398cdf0c1d5Smjnelson
1399cdf0c1d5Smjnelson#
1400cdf0c1d5Smjnelson# flist_from_mercurial
1401cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1402cdf0c1d5Smjnelson# flist_from_wx
1403cdf0c1d5Smjnelson#
1404cdf0c1d5Smjnelsonfunction flist_from_mercurial
1405cdf0c1d5Smjnelson{
1406cdf0c1d5Smjnelson	typeset child=$1
1407cdf0c1d5Smjnelson	typeset parent=$2
1408cdf0c1d5Smjnelson
1409cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1410cdf0c1d5Smjnelson
1411cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1412cdf0c1d5Smjnelson		print		# Blank line for the \c above
1413cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1414cdf0c1d5Smjnelson		exit 1
1415cdf0c1d5Smjnelson	fi
1416cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1417cdf0c1d5Smjnelson
1418cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1419cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1420cdf0c1d5Smjnelson}
1421cdf0c1d5Smjnelson
1422cdf0c1d5Smjnelson#
1423cdf0c1d5Smjnelson# flist_from_subversion
1424cdf0c1d5Smjnelson#
1425cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1426cdf0c1d5Smjnelson#
1427cdf0c1d5Smjnelsonfunction flist_from_subversion
1428cdf0c1d5Smjnelson{
1429cdf0c1d5Smjnelson	CWS=$1
1430cdf0c1d5Smjnelson	OLDPWD=$2
1431cdf0c1d5Smjnelson
1432cdf0c1d5Smjnelson	cd $CWS
1433cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1434cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1435cdf0c1d5Smjnelson	print -u2 " Done."
1436cdf0c1d5Smjnelson	cd $OLDPWD
1437cdf0c1d5Smjnelson}
1438cdf0c1d5Smjnelson
1439daaffb31Sdpfunction env_from_flist
1440daaffb31Sdp{
1441daaffb31Sdp	[[ -r $FLIST ]] || return
1442daaffb31Sdp
1443daaffb31Sdp	#
1444daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1445daaffb31Sdp	# list.  Then copy those into our local versions of those
1446daaffb31Sdp	# variables if they have not been set already.
1447daaffb31Sdp	#
14487c478bd9Sstevel@tonic-gate	eval `sed -e "s/#.*$//" $FLIST | grep = `
14497c478bd9Sstevel@tonic-gate
1450cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1451cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1452cdf0c1d5Smjnelson		export CODEMGR_WS
1453cdf0c1d5Smjnelson	fi
14547c478bd9Sstevel@tonic-gate
1455daaffb31Sdp	#
1456daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1457daaffb31Sdp	#
1458cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1459daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1460cdf0c1d5Smjnelson		export CODEMGR_PARENT
1461daaffb31Sdp	fi
1462daaffb31Sdp}
1463daaffb31Sdp
146414983201Sdpfunction look_for_prog
146514983201Sdp{
146614983201Sdp	typeset path
146714983201Sdp	typeset ppath
146814983201Sdp	typeset progname=$1
146914983201Sdp
147014983201Sdp	ppath=$PATH
147114983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
147214983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1473cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
147414983201Sdp
147514983201Sdp	PATH=$ppath prog=`whence $progname`
147614983201Sdp	if [[ -n $prog ]]; then
147714983201Sdp		print $prog
147814983201Sdp	fi
147914983201Sdp}
148014983201Sdp
1481cdf0c1d5Smjnelsonfunction get_file_mode
1482cdf0c1d5Smjnelson{
1483cdf0c1d5Smjnelson	$PERL -e '
1484cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1485cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1486cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1487cdf0c1d5Smjnelson			exit 0;
1488cdf0c1d5Smjnelson		} else {
1489cdf0c1d5Smjnelson			exit 1;
1490cdf0c1d5Smjnelson		}
1491cdf0c1d5Smjnelson	    ' $1
1492cdf0c1d5Smjnelson}
1493cdf0c1d5Smjnelson
1494cdf0c1d5Smjnelsonfunction build_old_new_teamware
1495cdf0c1d5Smjnelson{
1496cdf0c1d5Smjnelson	typeset olddir="$1"
1497cdf0c1d5Smjnelson	typeset newdir="$2"
1498cdf0c1d5Smjnelson
1499cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1500cdf0c1d5Smjnelson	# get a readonly copy.
1501cdf0c1d5Smjnelson
1502cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1503cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1504cdf0c1d5Smjnelson	fi
1505cdf0c1d5Smjnelson
1506cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1507cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1508cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1509cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1510cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1511cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1512cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1513cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1514cdf0c1d5Smjnelson	# permissions that would result after check in.
1515cdf0c1d5Smjnelson
1516cdf0c1d5Smjnelson	#
1517cdf0c1d5Smjnelson	# Snag new version of file.
1518cdf0c1d5Smjnelson	#
1519cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1520cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1521cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1522cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1523cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1524cdf0c1d5Smjnelson	fi
1525cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1526cdf0c1d5Smjnelson
1527cdf0c1d5Smjnelson	#
1528cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1529cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1530cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1531cdf0c1d5Smjnelson	#
1532cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1533cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1534cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1535cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1536cdf0c1d5Smjnelson		# the old file.
1537cdf0c1d5Smjnelson
1538cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1539cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1540cdf0c1d5Smjnelson	else
1541cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1542cdf0c1d5Smjnelson			real_parent=$PWS
1543cdf0c1d5Smjnelson		else
1544cdf0c1d5Smjnelson			real_parent=$RWS
1545cdf0c1d5Smjnelson		fi
1546cdf0c1d5Smjnelson
1547cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1548cdf0c1d5Smjnelson
1549cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1550cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1551cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1552cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1553cdf0c1d5Smjnelson			else
1554cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1555cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1556cdf0c1d5Smjnelson			fi
1557cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1558cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1559cdf0c1d5Smjnelson		fi
1560cdf0c1d5Smjnelson	fi
1561cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1562cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1563cdf0c1d5Smjnelson	fi
1564cdf0c1d5Smjnelson}
1565cdf0c1d5Smjnelson
1566cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1567cdf0c1d5Smjnelson{
1568cdf0c1d5Smjnelson	typeset olddir="$1"
1569cdf0c1d5Smjnelson	typeset newdir="$2"
1570cdf0c1d5Smjnelson	typeset old_mode=
1571cdf0c1d5Smjnelson	typeset new_mode=
1572cdf0c1d5Smjnelson	typeset file
1573cdf0c1d5Smjnelson
1574cdf0c1d5Smjnelson	#
1575cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1576cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1577cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1578cdf0c1d5Smjnelson	#
1579cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1580cdf0c1d5Smjnelson		file="$PF"
1581cdf0c1d5Smjnelson	else
1582cdf0c1d5Smjnelson		file="$PDIR/$PF"
1583cdf0c1d5Smjnelson	fi
1584cdf0c1d5Smjnelson	file=`echo $file | sed 's#/#\\\/#g'`
1585cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1586cdf0c1d5Smjnelson	old_mode=`sed -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1587cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1588cdf0c1d5Smjnelson
1589cdf0c1d5Smjnelson	#
1590cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1591cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1592cdf0c1d5Smjnelson	#
1593cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1594cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1595cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1596cdf0c1d5Smjnelson			new_mode=755
1597cdf0c1d5Smjnelson		else
1598cdf0c1d5Smjnelson			new_mode=644
1599cdf0c1d5Smjnelson		fi
1600cdf0c1d5Smjnelson	fi
1601cdf0c1d5Smjnelson
1602cdf0c1d5Smjnelson	#
1603cdf0c1d5Smjnelson	# new version of the file.
1604cdf0c1d5Smjnelson	#
1605cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1606cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1607cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1608cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1609cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1610cdf0c1d5Smjnelson		else
1611cdf0c1d5Smjnelson			# should never happen
1612cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1613cdf0c1d5Smjnelson		fi
1614cdf0c1d5Smjnelson	fi
1615cdf0c1d5Smjnelson
1616cdf0c1d5Smjnelson	#
1617cdf0c1d5Smjnelson	# parent's version of the file
1618cdf0c1d5Smjnelson	#
1619cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1620cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1621cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1622cdf0c1d5Smjnelson	#
1623cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1624cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1625cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1626cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1627cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1628cdf0c1d5Smjnelson
1629cdf0c1d5Smjnelson		if [ $? -ne 0 ]; then
1630cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1631cdf0c1d5Smjnelson		else
1632cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1633cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1634cdf0c1d5Smjnelson			else
1635cdf0c1d5Smjnelson				# should never happen
1636cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1637cdf0c1d5Smjnelson			fi
1638cdf0c1d5Smjnelson		fi
1639cdf0c1d5Smjnelson	fi
1640cdf0c1d5Smjnelson}
1641cdf0c1d5Smjnelson
1642cdf0c1d5Smjnelsonfunction build_old_new_subversion
1643cdf0c1d5Smjnelson{
1644cdf0c1d5Smjnelson	typeset olddir="$1"
1645cdf0c1d5Smjnelson	typeset newdir="$2"
1646cdf0c1d5Smjnelson
1647cdf0c1d5Smjnelson	# Snag new version of file.
1648cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1649cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1650cdf0c1d5Smjnelson
1651cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1652cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1653cdf0c1d5Smjnelson	else
1654cdf0c1d5Smjnelson		# Get the parent's version of the file.
1655cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
1656cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
1657cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
1658cdf0c1d5Smjnelson		fi
1659cdf0c1d5Smjnelson	fi
1660cdf0c1d5Smjnelson}
1661cdf0c1d5Smjnelson
1662cdf0c1d5Smjnelsonfunction build_old_new_unknown
1663cdf0c1d5Smjnelson{
1664cdf0c1d5Smjnelson	typeset olddir="$1"
1665cdf0c1d5Smjnelson	typeset newdir="$2"
1666cdf0c1d5Smjnelson
1667cdf0c1d5Smjnelson	#
1668cdf0c1d5Smjnelson	# Snag new version of file.
1669cdf0c1d5Smjnelson	#
1670cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1671cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1672cdf0c1d5Smjnelson
1673cdf0c1d5Smjnelson	#
1674cdf0c1d5Smjnelson	# Snag the parent's version of the file.
1675cdf0c1d5Smjnelson	#
1676cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
1677cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1678cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1679cdf0c1d5Smjnelson	fi
1680cdf0c1d5Smjnelson}
1681cdf0c1d5Smjnelson
1682cdf0c1d5Smjnelsonfunction build_old_new
1683cdf0c1d5Smjnelson{
1684cdf0c1d5Smjnelson	typeset WDIR=$1
1685cdf0c1d5Smjnelson	typeset PWS=$2
1686cdf0c1d5Smjnelson	typeset PDIR=$3
1687cdf0c1d5Smjnelson	typeset PF=$4
1688cdf0c1d5Smjnelson	typeset CWS=$5
1689cdf0c1d5Smjnelson	typeset DIR=$6
1690cdf0c1d5Smjnelson	typeset F=$7
1691cdf0c1d5Smjnelson
1692cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
1693cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
1694cdf0c1d5Smjnelson
1695cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
1696cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
1697cdf0c1d5Smjnelson
1698cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1699cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
1700cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
1701cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
1702cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
1703cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
1704cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
1705cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
1706cdf0c1d5Smjnelson	fi
1707cdf0c1d5Smjnelson
1708cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
1709cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
1710cdf0c1d5Smjnelson		return 1
1711cdf0c1d5Smjnelson	fi
1712cdf0c1d5Smjnelson	return 0
1713cdf0c1d5Smjnelson}
1714cdf0c1d5Smjnelson
1715cdf0c1d5Smjnelson
1716daaffb31Sdp#
1717daaffb31Sdp# Usage message.
1718daaffb31Sdp#
1719daaffb31Sdpfunction usage
1720daaffb31Sdp{
1721daaffb31Sdp	print 'Usage:\twebrev [common-options]
1722daaffb31Sdp	webrev [common-options] ( <file> | - )
1723daaffb31Sdp	webrev [common-options] -w <wx file>
1724daaffb31Sdp
1725daaffb31SdpOptions:
1726daaffb31Sdp	-O: Print bugids/arc cases suitable for OpenSolaris.
1727daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
1728daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
1729daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
1730daaffb31Sdp	-w <wxfile>: Use specified wx active file.
1731daaffb31Sdp
1732daaffb31SdpEnvironment:
1733daaffb31Sdp	WDIR: Control the output directory.
1734daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
1735daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
1736daaffb31Sdp
1737cdf0c1d5SmjnelsonSCM Specific Options:
1738cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
1739cdf0c1d5Smjnelson
1740daaffb31SdpSCM Environment:
1741cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
1742cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
1743daaffb31Sdp'
1744daaffb31Sdp
1745daaffb31Sdp	exit 2
1746daaffb31Sdp}
1747daaffb31Sdp
1748daaffb31Sdp#
1749daaffb31Sdp#
1750daaffb31Sdp# Main program starts here
1751daaffb31Sdp#
1752daaffb31Sdp#
1753daaffb31Sdp
1754daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1755daaffb31Sdp
1756daaffb31Sdpset +o noclobber
1757daaffb31Sdp
1758cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
1759cdf0c1d5Smjnelson
176014983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
176114983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
1762cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
1763cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
176414983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
176514983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
176614983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
1767cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
1768cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
1769cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
1770cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
1771cdf0c1d5Smjnelson
177214983201Sdp
177314983201Sdpif [[ ! -x $PERL ]]; then
177414983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
177514983201Sdp	exit 1
1776daaffb31Sdpfi
177714983201Sdp
1778cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
1779cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
1780cdf0c1d5Smjnelson	exit 1
1781cdf0c1d5Smjnelsonfi
1782cdf0c1d5Smjnelson
178314983201Sdp#
178414983201Sdp# These aren't fatal, but we want to note them to the user.
178514983201Sdp# We don't warn on the absence of 'wx' until later when we've
178614983201Sdp# determined that we actually need to try to invoke it.
178714983201Sdp#
178814983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
178914983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
179014983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
1791daaffb31Sdp
1792daaffb31Sdp# Declare global total counters.
1793daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
1794daaffb31Sdp
179514983201Sdpflist_mode=
179614983201Sdpflist_file=
1797daaffb31Sdpiflag=
1798daaffb31Sdpoflag=
1799daaffb31Sdppflag=
1800daaffb31Sdplflag=
1801daaffb31Sdpwflag=
1802daaffb31SdpOflag=
1803*3df69ef3SDarren MoffatNflag=
1804*3df69ef3SDarren Moffatwhile getopts "i:o:p:lwON" opt
1805daaffb31Sdpdo
1806daaffb31Sdp	case $opt in
1807daaffb31Sdp	i)	iflag=1
1808daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
1809daaffb31Sdp
1810daaffb31Sdp	o)	oflag=1
1811daaffb31Sdp		WDIR=$OPTARG;;
1812daaffb31Sdp
1813daaffb31Sdp	p)	pflag=1
1814daaffb31Sdp		codemgr_parent=$OPTARG;;
1815daaffb31Sdp
1816daaffb31Sdp	#
1817daaffb31Sdp	# If -l has been specified, we need to abort further options
1818daaffb31Sdp	# processing, because subsequent arguments are going to be
1819daaffb31Sdp	# arguments to 'putback -n'.
1820daaffb31Sdp	#
1821daaffb31Sdp	l)	lflag=1
1822daaffb31Sdp		break;;
1823daaffb31Sdp
1824daaffb31Sdp	w)	wflag=1;;
1825daaffb31Sdp
1826daaffb31Sdp	O)	Oflag=1;;
1827daaffb31Sdp
1828*3df69ef3SDarren Moffat	N)	Nflag=1;;
1829*3df69ef3SDarren Moffat
1830daaffb31Sdp	?)	usage;;
1831daaffb31Sdp	esac
1832daaffb31Sdpdone
1833daaffb31Sdp
1834daaffb31SdpFLIST=/tmp/$$.flist
1835daaffb31Sdp
1836daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
1837daaffb31Sdp	usage
1838daaffb31Sdpfi
1839daaffb31Sdp
1840daaffb31Sdp#
1841daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
1842daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
1843daaffb31Sdp#
1844daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
1845daaffb31Sdp	parent_webrev="$codemgr_parent"
1846daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
1847daaffb31Sdpfi
1848daaffb31Sdp
1849daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
1850daaffb31Sdp	shift $(($OPTIND - 1))
1851daaffb31Sdp
1852daaffb31Sdp	if [[ $1 == "-" ]]; then
1853daaffb31Sdp		cat > $FLIST
185414983201Sdp		flist_mode="stdin"
185514983201Sdp		flist_done=1
185614983201Sdp		shift
1857daaffb31Sdp	elif [[ -n $1 ]]; then
185814983201Sdp		if [[ ! -r $1 ]]; then
1859daaffb31Sdp			print -u2 "$1: no such file or not readable"
1860daaffb31Sdp			usage
1861daaffb31Sdp		fi
1862daaffb31Sdp		cat $1 > $FLIST
186314983201Sdp		flist_mode="file"
186414983201Sdp		flist_file=$1
186514983201Sdp		flist_done=1
186614983201Sdp		shift
1867daaffb31Sdp	else
186814983201Sdp		flist_mode="auto"
1869daaffb31Sdp	fi
1870daaffb31Sdpfi
1871daaffb31Sdp
1872daaffb31Sdp#
1873daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
1874daaffb31Sdp# is in use.
1875daaffb31Sdp#
1876cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
1877cdf0c1d5Smjnelsoncase "$SCM_MODE" in
1878cdf0c1d5Smjnelsonteamware|mercurial|subversion)
1879cdf0c1d5Smjnelson	;;
1880cdf0c1d5Smjnelsonunknown)
1881cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
1882cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
1883cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
18847c478bd9Sstevel@tonic-gate		exit 1
18857c478bd9Sstevel@tonic-gate	fi
1886cdf0c1d5Smjnelson	;;
1887cdf0c1d5Smjnelson*)
1888cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
1889cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
1890cdf0c1d5Smjnelson		exit 1
1891cdf0c1d5Smjnelson	fi
1892cdf0c1d5Smjnelson	;;
1893cdf0c1d5Smjnelsonesac
18947c478bd9Sstevel@tonic-gate
1895daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
1896daaffb31Sdp
1897daaffb31Sdpif [[ -n $lflag ]]; then
1898daaffb31Sdp	#
1899daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
1900daaffb31Sdp	# then generate the file list by extracting file names from a
1901daaffb31Sdp	# putback -n.
1902daaffb31Sdp	#
1903daaffb31Sdp	shift $(($OPTIND - 1))
1904cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1905daaffb31Sdp		flist_from_teamware "$*"
1906cdf0c1d5Smjnelson	else
1907cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
1908cdf0c1d5Smjnelson		exit 1
1909cdf0c1d5Smjnelson	fi
1910daaffb31Sdp	flist_done=1
1911daaffb31Sdp	shift $#
1912daaffb31Sdpelif [[ -n $wflag ]]; then
1913daaffb31Sdp	#
1914daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
1915daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
1916daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
1917daaffb31Sdp	# in building the index.html file.
1918daaffb31Sdp	#
1919daaffb31Sdp	shift $(($OPTIND - 1))
1920daaffb31Sdp	wxfile=$1
1921daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
1922daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
1923daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
1924daaffb31Sdp		fi
1925daaffb31Sdp	fi
1926daaffb31Sdp
1927daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
1928daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
1929daaffb31Sdp
1930cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
1931cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
1932cdf0c1d5Smjnelson		usage
1933cdf0c1d5Smjnelson	fi
1934cdf0c1d5Smjnelson
1935daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
1936daaffb31Sdp	flist_from_wx $wxfile
1937daaffb31Sdp	flist_done=1
1938daaffb31Sdp	if [[ -n "$*" ]]; then
1939daaffb31Sdp		shift
1940daaffb31Sdp	fi
194114983201Sdpelif [[ $flist_mode == "stdin" ]]; then
194214983201Sdp	print -u2 " File list from: standard input"
194314983201Sdpelif [[ $flist_mode == "file" ]]; then
194414983201Sdp	print -u2 " File list from: $flist_file"
1945daaffb31Sdpfi
1946daaffb31Sdp
1947daaffb31Sdpif [[ $# -gt 0 ]]; then
194814983201Sdp	print -u2 "WARNING: unused arguments: $*"
1949daaffb31Sdpfi
1950daaffb31Sdp
1951daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
1952daaffb31Sdp	#
1953daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
1954daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
1955daaffb31Sdp	#
1956daaffb31Sdp	#      1) on the command line (only for the parent)
1957daaffb31Sdp	#      2) in the user environment
1958daaffb31Sdp	#      3) in the flist
1959daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
1960daaffb31Sdp	#
1961daaffb31Sdp
1962daaffb31Sdp	#
1963daaffb31Sdp	# Here is case (2): the user environment
1964daaffb31Sdp	#
1965daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
1966daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
1967daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
19687c478bd9Sstevel@tonic-gate		exit 1
19697c478bd9Sstevel@tonic-gate	fi
19707c478bd9Sstevel@tonic-gate
1971daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
1972daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
1973daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
1974daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
19757c478bd9Sstevel@tonic-gate		exit 1
19767c478bd9Sstevel@tonic-gate	fi
19777c478bd9Sstevel@tonic-gate
1978daaffb31Sdp	#
1979daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
1980daaffb31Sdp	# list, then see if we can get it by probing for wx.
1981daaffb31Sdp	#
198214983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
198314983201Sdp		if [[ ! -x $WX ]]; then
198414983201Sdp			print -u2 "WARNING: wx not found!"
1985daaffb31Sdp		fi
19867c478bd9Sstevel@tonic-gate
1987daaffb31Sdp		#
1988daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
1989daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
1990daaffb31Sdp		# hang asking us to initialize our wx information.
1991daaffb31Sdp		#
199214983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
1993daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
1994daaffb31Sdp			$WX list -w > $FLIST
1995daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
1996daaffb31Sdp			wxfile=/tmp/$$.wx_comments
1997daaffb31Sdp			print -u2 "done"
1998daaffb31Sdp			flist_done=1
1999daaffb31Sdp		fi
2000daaffb31Sdp	fi
2001daaffb31Sdp
2002daaffb31Sdp	#
2003daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2004daaffb31Sdp	# from the command line), eval it to extract environment variables from
2005daaffb31Sdp	# it: This is step (3).
2006daaffb31Sdp	#
2007daaffb31Sdp	env_from_flist
2008daaffb31Sdp
2009daaffb31Sdp	#
2010daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2011daaffb31Sdp	# it from teamware.
2012daaffb31Sdp	#
2013daaffb31Sdp	if [[ -z $flist_done ]]; then
2014daaffb31Sdp		flist_from_teamware
2015daaffb31Sdp		env_from_flist
2016daaffb31Sdp	fi
2017daaffb31Sdp
2018daaffb31Sdp	#
2019daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2020daaffb31Sdp	# from workspace.
2021daaffb31Sdp	#
2022cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2023daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2024daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2025daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2026daaffb31Sdp		exit 1
2027daaffb31Sdp	fi
2028daaffb31Sdp
2029daaffb31Sdp	#
2030cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2031cdf0c1d5Smjnelson	# webrev title.
2032cdf0c1d5Smjnelson	#
2033cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2034cdf0c1d5Smjnelson
2035cdf0c1d5Smjnelson	#
2036daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2037daaffb31Sdp	#
2038daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2039daaffb31Sdp	CWS=$codemgr_ws
2040daaffb31Sdp	PWS=$codemgr_parent
2041cdf0c1d5Smjnelson
2042cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2043cdf0c1d5Smjnelson
2044cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2045cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2046cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2047cdf0c1d5Smjnelson
2048cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2049cdf0c1d5Smjnelson
2050cdf0c1d5Smjnelson	#
2051cdf0c1d5Smjnelson	# Parent can either be specified with -p
2052cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2053cdf0c1d5Smjnelson	# or taken from hg's default path.
2054cdf0c1d5Smjnelson	#
2055cdf0c1d5Smjnelson
2056cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2057cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2058cdf0c1d5Smjnelson	fi
2059cdf0c1d5Smjnelson
2060cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2061cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2062cdf0c1d5Smjnelson	fi
2063cdf0c1d5Smjnelson
2064cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2065cdf0c1d5Smjnelson	CWS=$codemgr_ws
2066cdf0c1d5Smjnelson	PWS=$codemgr_parent
2067cdf0c1d5Smjnelson
2068cdf0c1d5Smjnelson	#
2069cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2070cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2071cdf0c1d5Smjnelson	#
2072cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2073cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2074cdf0c1d5Smjnelson	else
2075cdf0c1d5Smjnelson		real_parent=$PWS
2076cdf0c1d5Smjnelson	fi
2077cdf0c1d5Smjnelson
2078cdf0c1d5Smjnelson	#
2079cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2080cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2081cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2082cdf0c1d5Smjnelson	# files mentioned in the flist.
2083cdf0c1d5Smjnelson	#
2084cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2085cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2086cdf0c1d5Smjnelson		flist_done=1
2087cdf0c1d5Smjnelson	fi
2088cdf0c1d5Smjnelson
2089cdf0c1d5Smjnelson	#
2090cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2091cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2092cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2093cdf0c1d5Smjnelson	# in the user-specified flist.
2094cdf0c1d5Smjnelson	#
2095cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2096cdf0c1d5Smjnelson		env_from_flist
2097cdf0c1d5Smjnelson	fi
2098cdf0c1d5Smjnelson
2099cdf0c1d5Smjnelson	#
2100cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2101cdf0c1d5Smjnelson	#
2102cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2103cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2104cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2105cdf0c1d5Smjnelson		print " Done."
2106cdf0c1d5Smjnelson	fi
2107cdf0c1d5Smjnelson
2108cdf0c1d5Smjnelson	#
2109cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2110cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2111cdf0c1d5Smjnelson	# if we don't have one.
2112cdf0c1d5Smjnelson	#
2113cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2114cdf0c1d5Smjnelson		eval `sed -e "s/#.*$//" $wxfile | grep HG_PARENT=`
2115cdf0c1d5Smjnelson	fi
2116cdf0c1d5Smjnelson
2117cdf0c1d5Smjnelson	#
2118cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2119cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2120cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2121cdf0c1d5Smjnelson	#
2122cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2123cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2124cdf0c1d5Smjnelson		    eval `sed -e "s/#.*$//" | grep HG_PARENT=`
2125cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2126cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2127cdf0c1d5Smjnelson		exit 1
2128cdf0c1d5Smjnelson	fi
2129cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2130cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2131cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2132cdf0c1d5Smjnelson	else
2133cdf0c1d5Smjnelson		svn info | while read line; do
2134cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2135cdf0c1d5Smjnelson				url=${line#URL: }
2136cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2137cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2138cdf0c1d5Smjnelson			fi
2139cdf0c1d5Smjnelson		done
2140cdf0c1d5Smjnelson
2141cdf0c1d5Smjnelson		rel=${url#$repo}
2142cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2143cdf0c1d5Smjnelson	fi
2144cdf0c1d5Smjnelson
2145cdf0c1d5Smjnelson	#
2146cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2147cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2148cdf0c1d5Smjnelson	#
2149cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2150cdf0c1d5Smjnelson
2151cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2152cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2153cdf0c1d5Smjnelson	fi
2154cdf0c1d5Smjnelsonelse
2155cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2156cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2157cdf0c1d5Smjnelson    else
2158cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2159cdf0c1d5Smjnelson    fi
2160cdf0c1d5Smjnelson
2161cdf0c1d5Smjnelson    env_from_flist
2162cdf0c1d5Smjnelson
2163cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2164cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2165cdf0c1d5Smjnelson	exit 1
2166cdf0c1d5Smjnelson    fi
2167cdf0c1d5Smjnelson
2168cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2169cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2170cdf0c1d5Smjnelson	exit 1
2171cdf0c1d5Smjnelson    fi
2172cdf0c1d5Smjnelson
2173cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2174cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2175daaffb31Sdpfi
2176daaffb31Sdp
2177daaffb31Sdp#
2178daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2179daaffb31Sdp# webrev-info file in the workspace directory.
2180daaffb31Sdp#
2181daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2182daaffb31Sdp	iflag=1
2183daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2184daaffb31Sdpfi
2185daaffb31Sdp
2186daaffb31Sdpif [[ -n $iflag ]]; then
2187daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2188daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2189daaffb31Sdp		    "not readable."
2190daaffb31Sdp		exit 1
2191daaffb31Sdp	else
2192daaffb31Sdp		#
2193daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2194daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2195daaffb31Sdp		#
2196daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2197daaffb31Sdp	fi
2198daaffb31Sdpfi
2199daaffb31Sdp
2200daaffb31Sdp#
2201daaffb31Sdp# Output directory.
2202daaffb31Sdp#
2203daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2204daaffb31Sdp
2205daaffb31Sdp#
2206daaffb31Sdp# Name of the webrev, derived from the workspace name; in the
2207daaffb31Sdp# future this could potentially be an option.
2208daaffb31Sdp#
2209daaffb31SdpWNAME=${CWS##*/}
2210daaffb31Sdp
2211e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
22127c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
22137c478bd9Sstevel@tonic-gatefi
2214daaffb31Sdp
2215daaffb31Sdpif [[ ! -d $WDIR ]]; then
2216daaffb31Sdp	mkdir -p $WDIR
2217daaffb31Sdp	[[ $? != 0 ]] && exit 1
22187c478bd9Sstevel@tonic-gatefi
22197c478bd9Sstevel@tonic-gate
2220daaffb31Sdp#
2221daaffb31Sdp# Summarize what we're going to do.
2222daaffb31Sdp#
2223cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2224cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2225cdf0c1d5Smjnelsonelse
2226daaffb31Sdp	print "      Workspace: $CWS"
2227cdf0c1d5Smjnelsonfi
2228daaffb31Sdpif [[ -n $parent_webrev ]]; then
2229daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2230daaffb31Sdpelse
2231cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2232cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2233cdf0c1d5Smjnelson			| sed -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2234cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2235cdf0c1d5Smjnelson	else
2236daaffb31Sdp		print "Compare against: $PWS"
2237daaffb31Sdp	fi
2238cdf0c1d5Smjnelsonfi
2239daaffb31Sdp
2240daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2241daaffb31Sdpprint "      Output to: $WDIR"
2242daaffb31Sdp
2243daaffb31Sdp#
22447c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2245daaffb31Sdp#
2246daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
22477c478bd9Sstevel@tonic-gate
2248daaffb31Sdp#
2249daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2250daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2251daaffb31Sdp#
2252daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2253daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2254daaffb31Sdp[[ -n "$Oflag" ]] && \
2255daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
22567c478bd9Sstevel@tonic-gate
2257daaffb31Sdp#
2258daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2259daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2260daaffb31Sdp#
2261daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2262daaffb31Sdp#    SACURL.  See sac2url().
2263daaffb31Sdp#
2264daaffb31SdpSACURL='http://sac.eng.sun.com'
2265daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2266e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2267daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
22687c478bd9Sstevel@tonic-gate
2269daaffb31Sdprm -f $WDIR/$WNAME.patch
2270daaffb31Sdprm -f $WDIR/$WNAME.ps
2271daaffb31Sdprm -f $WDIR/$WNAME.pdf
22727c478bd9Sstevel@tonic-gate
2273daaffb31Sdptouch $WDIR/$WNAME.patch
22747c478bd9Sstevel@tonic-gate
2275daaffb31Sdpprint "   Output Files:"
2276daaffb31Sdp
2277daaffb31Sdp#
2278daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2279daaffb31Sdp#
2280daaffb31Sdpsed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2281daaffb31SdpFLIST=/tmp/$$.flist.clean
2282daaffb31Sdp
2283daaffb31Sdp#
2284cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2285cdf0c1d5Smjnelson#
2286cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2287cdf0c1d5Smjnelson	#
2288cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2289cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2290cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2291cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2292cdf0c1d5Smjnelson	#    keep only the old name.
2293cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2294cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2295cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2296cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2297cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2298cdf0c1d5Smjnelson	#
2299cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2300cdf0c1d5Smjnelson	sed '
2301cdf0c1d5Smjnelson		s#^[^ ]* ##
2302cdf0c1d5Smjnelson		s#/#\\\/#g
2303cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2304cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2305cdf0c1d5Smjnelson
2306cdf0c1d5Smjnelson	#
2307cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2308cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2309cdf0c1d5Smjnelson	#
2310cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2311cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2312cdf0c1d5Smjnelson	    sed -n -f $SEDFILE > $HG_PARENT_MANIFEST
2313cdf0c1d5Smjnelsonfi
2314cdf0c1d5Smjnelson
2315cdf0c1d5Smjnelson#
2316daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2317daaffb31Sdp#
2318daaffb31Sdpcat $FLIST | while read LINE
23197c478bd9Sstevel@tonic-gatedo
23207c478bd9Sstevel@tonic-gate	set - $LINE
23217c478bd9Sstevel@tonic-gate	P=$1
23227c478bd9Sstevel@tonic-gate
2323daaffb31Sdp	#
2324daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2325daaffb31Sdp	# file that has been modified or created in the child.  A file
2326daaffb31Sdp	# that is renamed in the child workspace has two names on the
2327daaffb31Sdp	# line: new name followed by the old name.
2328daaffb31Sdp	#
2329daaffb31Sdp	oldname=""
2330daaffb31Sdp	oldpath=""
2331daaffb31Sdp	rename=
2332daaffb31Sdp	if [[ $# -eq 2 ]]; then
23337c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2334daaffb31Sdp		oldname=" (was $PP)"
2335daaffb31Sdp		oldpath="$PP"
2336daaffb31Sdp		rename=1
23377c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2338daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
23397c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
23407c478bd9Sstevel@tonic-gate		fi
23417c478bd9Sstevel@tonic-gate
23427c478bd9Sstevel@tonic-gate		PF=${PP##*/}
23437c478bd9Sstevel@tonic-gate
23447c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2345daaffb31Sdp	        if [[ $DIR == $P ]]; then
23467c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
23477c478bd9Sstevel@tonic-gate		fi
23487c478bd9Sstevel@tonic-gate
23497c478bd9Sstevel@tonic-gate		F=${P##*/}
2350daaffb31Sdp
23517c478bd9Sstevel@tonic-gate        else
23527c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2353daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
23547c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
23557c478bd9Sstevel@tonic-gate		fi
23567c478bd9Sstevel@tonic-gate
23577c478bd9Sstevel@tonic-gate		F=${P##*/}
23587c478bd9Sstevel@tonic-gate
23597c478bd9Sstevel@tonic-gate		PP=$P
23607c478bd9Sstevel@tonic-gate		PDIR=$DIR
23617c478bd9Sstevel@tonic-gate		PF=$F
23627c478bd9Sstevel@tonic-gate	fi
23637c478bd9Sstevel@tonic-gate
2364daaffb31Sdp	COMM=`getcomments html $P $PP`
23657c478bd9Sstevel@tonic-gate
2366daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
23677c478bd9Sstevel@tonic-gate
23687c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
23697c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
23707c478bd9Sstevel@tonic-gate
2371daaffb31Sdp	#
2372daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2373daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2374e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2375daaffb31Sdp	#
2376e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2377daaffb31Sdp		pclosed=${P##usr/closed/}
2378e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2379e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2380daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2381daaffb31Sdp			    "mode review"
2382daaffb31Sdp			continue
2383daaffb31Sdp		fi
2384daaffb31Sdp	fi
2385daaffb31Sdp
2386daaffb31Sdp	#
2387cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2388daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2389daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2390daaffb31Sdp	#
2391daaffb31Sdp
2392cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
23937c478bd9Sstevel@tonic-gate	    continue
23947c478bd9Sstevel@tonic-gate
2395cdf0c1d5Smjnelson	#
2396cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2397cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2398cdf0c1d5Smjnelson	# consistent environment.
2399cdf0c1d5Smjnelson	#
2400cdf0c1d5Smjnelson	OWD=$PWD
2401daaffb31Sdp	cd $WDIR/raw_files
2402daaffb31Sdp	ofile=old/$PDIR/$PF
2403daaffb31Sdp	nfile=new/$DIR/$F
24047c478bd9Sstevel@tonic-gate
2405daaffb31Sdp	mv_but_nodiff=
2406daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2407daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2408daaffb31Sdp		mv_but_nodiff=1
2409daaffb31Sdp	fi
2410daaffb31Sdp
2411daaffb31Sdp	#
2412daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2413daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2414daaffb31Sdp	#
2415daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2416daaffb31Sdp	#	  diff and an 'add' diff
2417daaffb31Sdp	#	- new files and deleted files must be handled specially
2418daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2419daaffb31Sdp	#	  (and hence renames) as of this writing.
2420daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2421daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2422daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2423daaffb31Sdp	#         transformations:
2424daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2425daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2426daaffb31Sdp	#
2427daaffb31Sdp	cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2428daaffb31Sdp	cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2429daaffb31Sdp
2430daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2431daaffb31Sdp	if [[ -z $rename ]]; then
2432e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2433daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2434daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2435e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2436daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2437daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2438daaffb31Sdp		else
2439daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2440daaffb31Sdp		fi
2441daaffb31Sdp	else
2442daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2443daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2444daaffb31Sdp
2445daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2446daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2447daaffb31Sdp
2448daaffb31Sdp	fi
2449daaffb31Sdp
2450daaffb31Sdp	#
2451daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2452daaffb31Sdp	# whole wad.
2453daaffb31Sdp	#
2454daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2455daaffb31Sdp
2456daaffb31Sdp	print " patch\c"
2457daaffb31Sdp
2458daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2459daaffb31Sdp
2460daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2461daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2462daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
24637c478bd9Sstevel@tonic-gate		print " cdiffs\c"
24647c478bd9Sstevel@tonic-gate
2465daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2466daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2467daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2468daaffb31Sdp
24697c478bd9Sstevel@tonic-gate		print " udiffs\c"
24707c478bd9Sstevel@tonic-gate
24717c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2472daaffb31Sdp			$WDIFF -c "$COMM" \
2473daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2474daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2475daaffb31Sdp			if [[ $? -eq 0 ]]; then
24767c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2477daaffb31Sdp			else
2478daaffb31Sdp				print " wdiffs[fail]\c"
2479daaffb31Sdp			fi
24807c478bd9Sstevel@tonic-gate		fi
24817c478bd9Sstevel@tonic-gate
2482daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2483daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
24847c478bd9Sstevel@tonic-gate		print " sdiffs\c"
24857c478bd9Sstevel@tonic-gate
24867c478bd9Sstevel@tonic-gate		print " frames\c"
24877c478bd9Sstevel@tonic-gate
24887c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
24897c478bd9Sstevel@tonic-gate
2490daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2491daaffb31Sdp
2492daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2493daaffb31Sdp		# renamed file: may also have differences
2494daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2495daaffb31Sdp	elif [[ -f $nfile ]]; then
24967c478bd9Sstevel@tonic-gate		# new file: count added lines
2497daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2498daaffb31Sdp	elif [[ -f $ofile ]]; then
24997c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2500daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
25017c478bd9Sstevel@tonic-gate	fi
25027c478bd9Sstevel@tonic-gate
2503daaffb31Sdp	#
2504daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
2505daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
2506daaffb31Sdp	# tree-killing to print out the contents of deleted files).
2507daaffb31Sdp	#
2508daaffb31Sdp	if [[ -f $nfile ]]; then
2509daaffb31Sdp		ocr=$ofile
2510daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
2511daaffb31Sdp
2512daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
2513daaffb31Sdp			textcomm=`getcomments text $P $PP`
251414983201Sdp			if [[ -x $CODEREVIEW ]]; then
251514983201Sdp				$CODEREVIEW -y "$textcomm" \
251614983201Sdp				    -e $ocr $nfile \
251714983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
251814983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
2519daaffb31Sdp				if [[ $? -eq 0 ]]; then
2520daaffb31Sdp					print " ps\c"
2521daaffb31Sdp				else
2522daaffb31Sdp					print " ps[fail]\c"
2523daaffb31Sdp				fi
2524daaffb31Sdp			fi
2525daaffb31Sdp		fi
252614983201Sdp	fi
2527daaffb31Sdp
2528cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
2529cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
25307c478bd9Sstevel@tonic-gate		print " old\c"
25317c478bd9Sstevel@tonic-gate	fi
25327c478bd9Sstevel@tonic-gate
2533daaffb31Sdp	if [[ -f $nfile ]]; then
2534daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
25357c478bd9Sstevel@tonic-gate		print " new\c"
25367c478bd9Sstevel@tonic-gate	fi
25377c478bd9Sstevel@tonic-gate
2538cdf0c1d5Smjnelson	cd $OWD
2539cdf0c1d5Smjnelson
2540daaffb31Sdp	print
25417c478bd9Sstevel@tonic-gatedone
25427c478bd9Sstevel@tonic-gate
2543daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
25447c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
2545daaffb31Sdp
254614983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
254714983201Sdp	print " Generating PDF: Skipped: no output available"
254814983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
254914983201Sdp	print " Generating PDF: \c"
255014983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
2551daaffb31Sdp	print "Done."
255214983201Sdpelse
255314983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
255414983201Sdpfi
25557c478bd9Sstevel@tonic-gate
2556e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
2557e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
2558e0e0293aSjmcp
2559e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
2560e0e0293aSjmcp	/usr/bin/find $WDIR -type d -name closed -exec /bin/rm -rf {} \;
2561e0e0293aSjmcpfi
2562e0e0293aSjmcp
25637c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
25647c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
25657c478bd9Sstevel@tonic-gate
25667c478bd9Sstevel@tonic-gatecd $CWS
25677c478bd9Sstevel@tonic-gate
25687c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
2569daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
25707c478bd9Sstevel@tonic-gate
2571daaffb31Sdpprint "     index.html: \c"
25727c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
25737c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
25747c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
25757c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
25767c478bd9Sstevel@tonic-gate
2577daaffb31Sdpprint "$HTML<head>$STDHEAD"
2578daaffb31Sdpprint "<title>$WNAME</title>"
2579daaffb31Sdpprint "</head>"
2580daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
2581daaffb31Sdpprint "<div class=\"summary\">"
2582daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
25837c478bd9Sstevel@tonic-gate
2584daaffb31Sdpprint "<table>"
25857c478bd9Sstevel@tonic-gate
2586daaffb31Sdp#
2587cdf0c1d5Smjnelson# Get the preparer's name:
2588daaffb31Sdp#
2589cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
2590cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
2591cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
2592cdf0c1d5Smjnelson#
2593cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
2594cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
2595cdf0c1d5Smjnelson#
2596cdf0c1d5Smjnelsonpreparer=
2597cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
2598cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
2599cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
2600cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
2601cdf0c1d5Smjnelson	fi
2602cdf0c1d5Smjnelsonfi
2603cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
2604cdf0c1d5Smjnelson	preparer=$(
2605cdf0c1d5Smjnelson	    $PERL -e '
2606cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
2607cdf0c1d5Smjnelson	        if ($login) {
2608cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
2609cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
2610cdf0c1d5Smjnelson	        } else {
2611cdf0c1d5Smjnelson	            printf "(unknown)\n";
2612cdf0c1d5Smjnelson	        }
2613cdf0c1d5Smjnelson	')
2614daaffb31Sdpfi
2615daaffb31Sdp
2616cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
2617cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
2618cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2619cdf0c1d5Smjnelson	print "(at $CWS_REV)"
2620cdf0c1d5Smjnelsonfi
2621cdf0c1d5Smjnelsonprint "</td></tr>"
2622daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
2623daaffb31Sdpif [[ -n $parent_webrev ]]; then
2624daaffb31Sdp	print "webrev at $parent_webrev"
2625daaffb31Sdpelse
2626daaffb31Sdp	print "$PWS"
2627cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
2628cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
2629cdf0c1d5Smjnelson	fi
2630daaffb31Sdpfi
2631daaffb31Sdpprint "</td></tr>"
2632daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
2633daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
2634daaffb31Sdpprint "</td></tr>"
2635daaffb31Sdp
2636daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
2637daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
2638daaffb31Sdp	print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
2639daaffb31Sdpfi
2640daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
2641daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
2642daaffb31Sdp	print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
2643daaffb31Sdpfi
2644daaffb31Sdp
2645daaffb31Sdpif [[ -n "$iflag" ]]; then
2646daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
2647daaffb31Sdp	cat /tmp/$$.include
2648daaffb31Sdp	print "</div></td></tr>"
2649daaffb31Sdpfi
2650daaffb31Sdpprint "</table>"
2651daaffb31Sdpprint "</div>"
2652daaffb31Sdp
2653daaffb31Sdp#
2654daaffb31Sdp# Second pass through the files: generate the rest of the index file
2655daaffb31Sdp#
2656daaffb31Sdpcat $FLIST | while read LINE
26577c478bd9Sstevel@tonic-gatedo
26587c478bd9Sstevel@tonic-gate	set - $LINE
26597c478bd9Sstevel@tonic-gate	P=$1
26607c478bd9Sstevel@tonic-gate
2661daaffb31Sdp	if [[ $# == 2 ]]; then
26627c478bd9Sstevel@tonic-gate		PP=$2
2663cdf0c1d5Smjnelson		oldname="$PP"
26647c478bd9Sstevel@tonic-gate	else
26657c478bd9Sstevel@tonic-gate		PP=$P
2666daaffb31Sdp		oldname=""
2667daaffb31Sdp	fi
2668daaffb31Sdp
2669cdf0c1d5Smjnelson	mv_but_nodiff=
2670cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
2671cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
2672cdf0c1d5Smjnelson		mv_but_nodiff=1
2673cdf0c1d5Smjnelson	fi
2674cdf0c1d5Smjnelson
2675daaffb31Sdp	DIR=${P%/*}
2676daaffb31Sdp	if [[ $DIR == $P ]]; then
2677daaffb31Sdp		DIR="."   # File at root of workspace
26787c478bd9Sstevel@tonic-gate	fi
26797c478bd9Sstevel@tonic-gate
26807c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
26817c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
26827c478bd9Sstevel@tonic-gate	# appear twice in the file list
26837c478bd9Sstevel@tonic-gate
26847c478bd9Sstevel@tonic-gate	F=$WDIR/$P
26857c478bd9Sstevel@tonic-gate
2686daaffb31Sdp	print "<p>"
26877c478bd9Sstevel@tonic-gate
26887c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
26897c478bd9Sstevel@tonic-gate
2690daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
2691daaffb31Sdp		print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
2692daaffb31Sdp		print "<a href=\"$P.udiff.html\">Udiffs</a>"
26937c478bd9Sstevel@tonic-gate
2694daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
2695daaffb31Sdp			print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
26967c478bd9Sstevel@tonic-gate		fi
26977c478bd9Sstevel@tonic-gate
2698daaffb31Sdp		print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
26997c478bd9Sstevel@tonic-gate
27007c478bd9Sstevel@tonic-gate		print "<a href=\"$P.frames.html\">Frames</a>"
27017c478bd9Sstevel@tonic-gate	else
2702daaffb31Sdp		print " ------ ------ ------"
27037c478bd9Sstevel@tonic-gate
2704daaffb31Sdp		if [[ -x $WDIFF ]]; then
27057c478bd9Sstevel@tonic-gate			print " ------"
27067c478bd9Sstevel@tonic-gate		fi
2707daaffb31Sdp
2708daaffb31Sdp		print " ------"
27097c478bd9Sstevel@tonic-gate	fi
27107c478bd9Sstevel@tonic-gate
27117c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
27127c478bd9Sstevel@tonic-gate
2713daaffb31Sdp	if [[ -f $F-.html ]]; then
2714daaffb31Sdp		print "<a href=\"$P-.html\">Old</a>"
27157c478bd9Sstevel@tonic-gate	else
2716daaffb31Sdp		print " ---"
27177c478bd9Sstevel@tonic-gate	fi
27187c478bd9Sstevel@tonic-gate
27197c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
27207c478bd9Sstevel@tonic-gate
2721daaffb31Sdp	if [[ -f $F.html ]]; then
2722daaffb31Sdp		print "<a href=\"$P.html\">New</a>"
27237c478bd9Sstevel@tonic-gate	else
2724daaffb31Sdp		print " ---"
27257c478bd9Sstevel@tonic-gate	fi
27267c478bd9Sstevel@tonic-gate
2727daaffb31Sdp	if [[ -f $F.patch ]]; then
2728daaffb31Sdp		print "<a href=\"$P.patch\">Patch</a>"
2729daaffb31Sdp	else
2730daaffb31Sdp		print " -----"
2731daaffb31Sdp	fi
2732daaffb31Sdp
2733daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
2734daaffb31Sdp		print "<a href=\"raw_files/new/$P\">Raw</a>"
2735daaffb31Sdp	else
2736daaffb31Sdp		print " ---"
2737daaffb31Sdp	fi
2738daaffb31Sdp
2739cdf0c1d5Smjnelson	print "<b>$P</b>"
2740cdf0c1d5Smjnelson
2741cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
2742cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
2743cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
2744cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
2745cdf0c1d5Smjnelson		else
2746cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
2747cdf0c1d5Smjnelson		fi
2748cdf0c1d5Smjnelson	fi
2749cdf0c1d5Smjnelson
2750cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
2751cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
2752cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
2753cdf0c1d5Smjnelson	fi
2754daaffb31Sdp
2755daaffb31Sdp	#
2756e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
2757daaffb31Sdp	#
2758daaffb31Sdp	if [ ! -z "$Oflag" ]; then
2759e0e0293aSjmcp		if [[ $P == usr/closed/* || \
2760e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
2761daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
2762daaffb31Sdp			    "this review</i>"
2763daaffb31Sdp		fi
2764daaffb31Sdp	fi
2765daaffb31Sdp
2766daaffb31Sdp	print "</p>"
27677c478bd9Sstevel@tonic-gate	# Insert delta comments
27687c478bd9Sstevel@tonic-gate
2769daaffb31Sdp	print "<blockquote><pre>"
2770daaffb31Sdp	getcomments html $P $PP
2771daaffb31Sdp	print "</pre>"
27727c478bd9Sstevel@tonic-gate
27737c478bd9Sstevel@tonic-gate	# Add additional comments comment
27747c478bd9Sstevel@tonic-gate
2775daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
27767c478bd9Sstevel@tonic-gate
27777c478bd9Sstevel@tonic-gate	# Add count of changes.
27787c478bd9Sstevel@tonic-gate
2779daaffb31Sdp	if [[ -f $F.count ]]; then
27807c478bd9Sstevel@tonic-gate	    cat $F.count
27817c478bd9Sstevel@tonic-gate	    rm $F.count
27827c478bd9Sstevel@tonic-gate	fi
2783cdf0c1d5Smjnelson
2784cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
2785cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
2786cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
2787cdf0c1d5Smjnelson
2788cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
2789cdf0c1d5Smjnelson		# 1) New executable files
2790cdf0c1d5Smjnelson		# 2) Permission changes of any kind
2791cdf0c1d5Smjnelson		# 3) Existing executable files
2792cdf0c1d5Smjnelson
2793cdf0c1d5Smjnelson		old_mode=
2794cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
2795cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
2796cdf0c1d5Smjnelson		fi
2797cdf0c1d5Smjnelson
2798cdf0c1d5Smjnelson		new_mode=
2799cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
2800cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
2801cdf0c1d5Smjnelson		fi
2802cdf0c1d5Smjnelson
2803cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
2804cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2805cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
2806cdf0c1d5Smjnelson			print "</span>"
2807cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
2808cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
2809cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2810cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
2811cdf0c1d5Smjnelson			print "</span>"
2812cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
2813cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2814cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
2815cdf0c1d5Smjnelson			print "</span>"
2816cdf0c1d5Smjnelson		fi
2817cdf0c1d5Smjnelson	fi
2818cdf0c1d5Smjnelson
2819daaffb31Sdp	print "</blockquote>"
28207c478bd9Sstevel@tonic-gatedone
28217c478bd9Sstevel@tonic-gate
2822daaffb31Sdpprint
2823daaffb31Sdpprint
2824cac38512Smjnelsonprint "<hr></hr>"
2825daaffb31Sdpprint "<p style=\"font-size: small\">"
28269a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
2827daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
2828daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
2829e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
2830daaffb31Sdpprint "</body>"
2831daaffb31Sdpprint "</html>"
28327c478bd9Sstevel@tonic-gate
28337c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
28347c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
28357c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
28367c478bd9Sstevel@tonic-gate
2837daaffb31Sdpprint "Done."
2838