xref: /titanic_53/usr/src/tools/scripts/webrev.sh (revision cdf0c1d55d9b3b6beaf994835440dfb01aef5cf0)
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#
227c478bd9Sstevel@tonic-gate# ident	"%Z%%M%	%I%	%E% SMI"
237c478bd9Sstevel@tonic-gate#
24cac38512Smjnelson# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate# Use is subject to license terms.
267c478bd9Sstevel@tonic-gate#
27*cdf0c1d5Smjnelson
28*cdf0c1d5Smjnelson#
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-gate#
39daaffb31Sdp# The following variable is set to SCCS delta date 20YY/MM/DD.
407c478bd9Sstevel@tonic-gate# Note this will have to be changed in 2100 or when SCCS has support for
417c478bd9Sstevel@tonic-gate# 4 digit years; whichever is the sooner!
427c478bd9Sstevel@tonic-gate#
437c478bd9Sstevel@tonic-gateWEBREV_UPDATED=20%E%
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
467c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
477c478bd9Sstevel@tonic-gateNEW_COLOR=blue
487c478bd9Sstevel@tonic-gate
49daaffb31SdpHTML='<?xml version="1.0"?>
50daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
51daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
52daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
53daaffb31Sdp
54daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
55daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
56daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
57daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
58daaffb31Sdp
59cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
60cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
61cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
62daaffb31Sdp<!--
63daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
64daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
65daaffb31Sdp   mechanism available in some browsers.
66daaffb31Sdp
67daaffb31Sdp   For example, to have all "removed" information be red instead of
68daaffb31Sdp   brown, set a rule in your userContent.css file like:
69daaffb31Sdp
70daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
71daaffb31Sdp-->
72daaffb31Sdp<style type="text/css" media="screen">
73daaffb31Sdpbody {
74daaffb31Sdp    background-color: #eeeeee;
75daaffb31Sdp}
76daaffb31Sdphr {
77daaffb31Sdp    border: none 0;
78daaffb31Sdp    border-top: 1px solid #aaa;
79daaffb31Sdp    height: 1px;
80daaffb31Sdp}
81daaffb31Sdpdiv.summary {
82daaffb31Sdp    font-size: .8em;
83daaffb31Sdp    border-bottom: 1px solid #aaa;
84daaffb31Sdp    padding-left: 1em;
85daaffb31Sdp    padding-right: 1em;
86daaffb31Sdp}
87daaffb31Sdpdiv.summary h2 {
88daaffb31Sdp    margin-bottom: 0.3em;
89daaffb31Sdp}
90daaffb31Sdpdiv.summary table th {
91daaffb31Sdp    text-align: right;
92daaffb31Sdp    vertical-align: top;
93daaffb31Sdp    white-space: nowrap;
94daaffb31Sdp}
95daaffb31Sdpspan.lineschanged {
96daaffb31Sdp    font-size: 0.7em;
97daaffb31Sdp}
98daaffb31Sdpspan.oldmarker {
99daaffb31Sdp    color: red;
100daaffb31Sdp    font-size: large;
101daaffb31Sdp    font-weight: bold;
102daaffb31Sdp}
103daaffb31Sdpspan.newmarker {
104daaffb31Sdp    color: green;
105daaffb31Sdp    font-size: large;
106daaffb31Sdp    font-weight: bold;
107daaffb31Sdp}
108daaffb31Sdpspan.removed {
109daaffb31Sdp    color: brown;
110daaffb31Sdp}
111daaffb31Sdpspan.changed {
112daaffb31Sdp    color: blue;
113daaffb31Sdp}
114daaffb31Sdpspan.new {
115daaffb31Sdp    color: blue;
116daaffb31Sdp    font-weight: bold;
117daaffb31Sdp}
118*cdf0c1d5Smjnelsonspan.chmod {
119*cdf0c1d5Smjnelson    font-size: 0.7em;
120*cdf0c1d5Smjnelson    color: #db7800;
121*cdf0c1d5Smjnelson}
122daaffb31Sdpa.print { font-size: x-small; }
123daaffb31Sdpa:hover { background-color: #ffcc99; }
124daaffb31Sdp</style>
125daaffb31Sdp
126daaffb31Sdp<style type="text/css" media="print">
127daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
128daaffb31Sdpspan.removed { color: #444; font-style: italic }
129daaffb31Sdpspan.changed { font-weight: bold; }
130daaffb31Sdpspan.new { font-weight: bold; }
131daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
132daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
133daaffb31Sdpa.print {display: none}
134daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
135daaffb31Sdp</style>
136daaffb31Sdp'
137daaffb31Sdp
138daaffb31Sdp#
139daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
140daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
141daaffb31Sdp#
142daaffb31SdpUDIFFCSS='
143daaffb31Sdp<style type="text/css" media="screen">
144daaffb31Sdpspan.new {
145daaffb31Sdp    color: blue;
146daaffb31Sdp    font-weight: normal;
147daaffb31Sdp}
148daaffb31Sdp</style>
149daaffb31Sdp'
150daaffb31Sdp
151daaffb31Sdp#
152daaffb31Sdp# input_cmd | html_quote | output_cmd
153daaffb31Sdp# or
154daaffb31Sdp# html_quote filename | output_cmd
1557c478bd9Sstevel@tonic-gate#
1567c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
1577c478bd9Sstevel@tonic-gate#
1587c478bd9Sstevel@tonic-gatehtml_quote()
1597c478bd9Sstevel@tonic-gate{
1607c478bd9Sstevel@tonic-gate	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
1617c478bd9Sstevel@tonic-gate}
1627c478bd9Sstevel@tonic-gate
163daaffb31Sdp#
164daaffb31Sdp# input_cmd | bug2url | output_cmd
165daaffb31Sdp#
166daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
167daaffb31Sdp#
168daaffb31Sdpbug2url()
1697c478bd9Sstevel@tonic-gate{
170daaffb31Sdp	sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
171daaffb31Sdp}
172daaffb31Sdp
1737c478bd9Sstevel@tonic-gate#
174daaffb31Sdp# input_cmd | sac2url | output_cmd
1757c478bd9Sstevel@tonic-gate#
176daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
177daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
178daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
179daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
1807c478bd9Sstevel@tonic-gate#
181daaffb31Sdpsac2url()
182daaffb31Sdp{
183e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
1840a30ef2cSstevel	    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'
185daaffb31Sdp	else
186daaffb31Sdp	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
187daaffb31Sdp	fi
188daaffb31Sdp}
189daaffb31Sdp
1907c478bd9Sstevel@tonic-gate#
191daaffb31Sdp# strip_unchanged <infile> | output_cmd
1927c478bd9Sstevel@tonic-gate#
193daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
194daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
1957c478bd9Sstevel@tonic-gate#
196daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
197daaffb31Sdp# identical lines are retained before and after the changed lines to
198daaffb31Sdp# provide some context.  The number of these lines is controlled by the
199*cdf0c1d5Smjnelson# variable C in the $AWK script below.
200daaffb31Sdp#
201daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
202daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
203daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
204daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
205daaffb31Sdp#
206daaffb31Sdpstrip_unchanged()
207daaffb31Sdp{
208*cdf0c1d5Smjnelson	$AWK '
209daaffb31Sdp	BEGIN	{ C = c = 20 }
210*cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
211daaffb31Sdp		if (c > C) {
212daaffb31Sdp			c -= C
213daaffb31Sdp			inx = 0
214daaffb31Sdp			if (c > C) {
215cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
216daaffb31Sdp				inx = c % C
217daaffb31Sdp				c = C
218daaffb31Sdp			}
219daaffb31Sdp
220daaffb31Sdp			for (i = 0; i < c; i++)
221daaffb31Sdp				print ln[(inx + i) % C]
222daaffb31Sdp		}
223daaffb31Sdp		c = 0;
224daaffb31Sdp		print
225daaffb31Sdp		next
226daaffb31Sdp	}
227daaffb31Sdp	{	if (c >= C) {
228daaffb31Sdp			ln[c % C] = $0
229daaffb31Sdp			c++;
230daaffb31Sdp			next;
231daaffb31Sdp		}
232daaffb31Sdp		c++;
233daaffb31Sdp		print
234daaffb31Sdp	}
235cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
236daaffb31Sdp
237daaffb31Sdp	' $1
238daaffb31Sdp}
239daaffb31Sdp
240daaffb31Sdp#
241daaffb31Sdp# sdiff_to_html
242daaffb31Sdp#
243daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
244daaffb31Sdp# processes the diff output to present the files as an HTML document with
245daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
246daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
247daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
248daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
249daaffb31Sdp# e.g.
250daaffb31Sdp#
251daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
252daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
253daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
254daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
255daaffb31Sdp#          1234567</a> my bugid' > <file>.html
256daaffb31Sdp#
257daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
258daaffb31Sdp# in the webrev tree.
259daaffb31Sdp#
260daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
261daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
262daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
263daaffb31Sdp# the editing codes, e.g.
2647c478bd9Sstevel@tonic-gate#
2657c478bd9Sstevel@tonic-gate#      8c8
2667c478bd9Sstevel@tonic-gate#      57a61
2677c478bd9Sstevel@tonic-gate#      63c66,76
2687c478bd9Sstevel@tonic-gate#      68,93d80
2697c478bd9Sstevel@tonic-gate#      106d90
2707c478bd9Sstevel@tonic-gate#      108,110d91
2717c478bd9Sstevel@tonic-gate#
272daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
273daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
274daaffb31Sdp#  into something like this:
2757c478bd9Sstevel@tonic-gate#
2767c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
2777c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
278daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
2797c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
2807c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
2817c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
2827c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
2837c478bd9Sstevel@tonic-gate#        :               :
2847c478bd9Sstevel@tonic-gate#
285daaffb31Sdp#  This script is then run on the original source file to generate the
286daaffb31Sdp#  HTML that corresponds to the source file.
2877c478bd9Sstevel@tonic-gate#
288daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
289daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
290daaffb31Sdp#  notice that the changes are color-coded:
2917c478bd9Sstevel@tonic-gate#
2927c478bd9Sstevel@tonic-gate#   black     - unchanged lines
2937c478bd9Sstevel@tonic-gate#   blue      - changed lines
2947c478bd9Sstevel@tonic-gate#   bold blue - new lines
2957c478bd9Sstevel@tonic-gate#   brown     - deleted lines
2967c478bd9Sstevel@tonic-gate#
297daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
298daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
299daaffb31Sdp#  Teamware's filemerge tool.
300daaffb31Sdp#
301daaffb31Sdpsdiff_to_html()
302daaffb31Sdp{
3037c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
3047c478bd9Sstevel@tonic-gate
305daaffb31Sdp	TNAME=$3
306daaffb31Sdp	TPATH=$4
307daaffb31Sdp	COMMENT=$5
308daaffb31Sdp
3097c478bd9Sstevel@tonic-gate	#
3107c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
3117c478bd9Sstevel@tonic-gate	#
312*cdf0c1d5Smjnelson	$AWK '
3137c478bd9Sstevel@tonic-gate	BEGIN	{
3147c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
315daaffb31Sdp		printf "function removed() "
316daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
317daaffb31Sdp		printf "function changed() "
318daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
319daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
3207c478bd9Sstevel@tonic-gate}
3217c478bd9Sstevel@tonic-gate	/^</	{next}
3227c478bd9Sstevel@tonic-gate	/^>/	{next}
3237c478bd9Sstevel@tonic-gate	/^---/	{next}
324daaffb31Sdp
3257c478bd9Sstevel@tonic-gate	{
3267c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
3277c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
3287c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
3297c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
3307c478bd9Sstevel@tonic-gate			if (n == 1)
3317c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
3327c478bd9Sstevel@tonic-gate			else
3337c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
3347c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
3357c478bd9Sstevel@tonic-gate			next
3367c478bd9Sstevel@tonic-gate		}
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
3397c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
3407c478bd9Sstevel@tonic-gate		s = r[1];
3417c478bd9Sstevel@tonic-gate		if (n == 1)
3427c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
3437c478bd9Sstevel@tonic-gate		else {
3447c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
3457c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
3467c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
3477c478bd9Sstevel@tonic-gate		}
3487c478bd9Sstevel@tonic-gate		next
3497c478bd9Sstevel@tonic-gate	}
3507c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
3517c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
3527c478bd9Sstevel@tonic-gate		n1 = r[1]
3537c478bd9Sstevel@tonic-gate		n2 = r[2]
3547c478bd9Sstevel@tonic-gate		if (n == 1)
355daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
3567c478bd9Sstevel@tonic-gate		else
357daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
3587c478bd9Sstevel@tonic-gate		next
3597c478bd9Sstevel@tonic-gate	}
3607c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
3617c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
3627c478bd9Sstevel@tonic-gate		n1 = r[1]
3637c478bd9Sstevel@tonic-gate		n2 = r[2]
3647c478bd9Sstevel@tonic-gate		final = n2
3657c478bd9Sstevel@tonic-gate		d1 = 0
3667c478bd9Sstevel@tonic-gate		if (n == 1)
367daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
3687c478bd9Sstevel@tonic-gate		else {
3697c478bd9Sstevel@tonic-gate			d1 = n2 - n1
370daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
3717c478bd9Sstevel@tonic-gate		}
3727c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
3737c478bd9Sstevel@tonic-gate		n1 = r[1]
3747c478bd9Sstevel@tonic-gate		n2 = r[2]
3757c478bd9Sstevel@tonic-gate		if (m > 1) {
3767c478bd9Sstevel@tonic-gate			d2  = n2 - n1
3777c478bd9Sstevel@tonic-gate			if (d2 > d1) {
3787c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
3797c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
3807c478bd9Sstevel@tonic-gate			}
3817c478bd9Sstevel@tonic-gate		}
3827c478bd9Sstevel@tonic-gate		printf "next}\n" ;
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate		next
3857c478bd9Sstevel@tonic-gate	}
3867c478bd9Sstevel@tonic-gate	}
3877c478bd9Sstevel@tonic-gate
388daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
389daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate	#
3927c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
3937c478bd9Sstevel@tonic-gate	#
394*cdf0c1d5Smjnelson	$AWK '
3957c478bd9Sstevel@tonic-gate	BEGIN	{
3967c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
397daaffb31Sdp		printf "function new() "
398daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
399daaffb31Sdp		printf "function changed() "
400daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
401daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
4027c478bd9Sstevel@tonic-gate	}
403daaffb31Sdp
4047c478bd9Sstevel@tonic-gate	/^</	{next}
4057c478bd9Sstevel@tonic-gate	/^>/	{next}
4067c478bd9Sstevel@tonic-gate	/^---/	{next}
407daaffb31Sdp
4087c478bd9Sstevel@tonic-gate	{
4097c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
4107c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
4117c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
4127c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
4137c478bd9Sstevel@tonic-gate			if (n == 1)
4147c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
4157c478bd9Sstevel@tonic-gate			else
4167c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
4177c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
4187c478bd9Sstevel@tonic-gate			next
4197c478bd9Sstevel@tonic-gate		}
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
4227c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
4237c478bd9Sstevel@tonic-gate		s = r[1];
4247c478bd9Sstevel@tonic-gate		if (n == 1)
4257c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
4267c478bd9Sstevel@tonic-gate		else {
4277c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
4287c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
4297c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
4307c478bd9Sstevel@tonic-gate		}
4317c478bd9Sstevel@tonic-gate		next
4327c478bd9Sstevel@tonic-gate	}
4337c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
4347c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
4357c478bd9Sstevel@tonic-gate		n1 = r[1]
4367c478bd9Sstevel@tonic-gate		n2 = r[2]
4377c478bd9Sstevel@tonic-gate		if (n == 1)
438daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
4397c478bd9Sstevel@tonic-gate		else
440daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
4417c478bd9Sstevel@tonic-gate		next
4427c478bd9Sstevel@tonic-gate	}
4437c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
4447c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
4457c478bd9Sstevel@tonic-gate		n1 = r[1]
4467c478bd9Sstevel@tonic-gate		n2 = r[2]
4477c478bd9Sstevel@tonic-gate		final = n2
4487c478bd9Sstevel@tonic-gate		d2 = 0;
4497c478bd9Sstevel@tonic-gate		if (n == 1) {
4507c478bd9Sstevel@tonic-gate			final = n1
451daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
4527c478bd9Sstevel@tonic-gate		} else {
4537c478bd9Sstevel@tonic-gate			d2 = n2 - n1
454daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
4557c478bd9Sstevel@tonic-gate		}
4567c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
4577c478bd9Sstevel@tonic-gate		n1 = r[1]
4587c478bd9Sstevel@tonic-gate		n2 = r[2]
4597c478bd9Sstevel@tonic-gate		if (m > 1) {
4607c478bd9Sstevel@tonic-gate			d1  = n2 - n1
4617c478bd9Sstevel@tonic-gate			if (d1 > d2) {
4627c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
4637c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
4647c478bd9Sstevel@tonic-gate			}
4657c478bd9Sstevel@tonic-gate		}
4667c478bd9Sstevel@tonic-gate		printf "next}\n" ;
4677c478bd9Sstevel@tonic-gate		next
4687c478bd9Sstevel@tonic-gate	}
4697c478bd9Sstevel@tonic-gate	}
470daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
4717c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
4727c478bd9Sstevel@tonic-gate
473daaffb31Sdp	#
474*cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
475daaffb31Sdp	#
476*cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
4777c478bd9Sstevel@tonic-gate
478*cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
4797c478bd9Sstevel@tonic-gate
480daaffb31Sdp	#
481daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
482daaffb31Sdp	#
483daaffb31Sdp	print "$HTML<head>$STDHEAD"
484*cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
485daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
486daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
487daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
488daaffb31Sdp	print "<table><tr valign=\"top\">"
489daaffb31Sdp	print "<td><pre>"
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
4927c478bd9Sstevel@tonic-gate
493daaffb31Sdp	print "</pre></td><td><pre>"
4947c478bd9Sstevel@tonic-gate
4957c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
4967c478bd9Sstevel@tonic-gate
497daaffb31Sdp	print "</pre></td>"
498daaffb31Sdp	print "</tr></table>"
499daaffb31Sdp	print "</body></html>"
5007c478bd9Sstevel@tonic-gate
501daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
502daaffb31Sdp	    "$COMMENT"
5037c478bd9Sstevel@tonic-gate}
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate
506daaffb31Sdp#
507daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
508daaffb31Sdp#
509daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
510daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
511daaffb31Sdp# and then emit the main frame.  Content is placed into:
512daaffb31Sdp#
513daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
514daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
515daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
516daaffb31Sdp#
517daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
518daaffb31Sdp#
5197c478bd9Sstevel@tonic-gatefunction framed_sdiff
5207c478bd9Sstevel@tonic-gate{
5217c478bd9Sstevel@tonic-gate	typeset TNAME=$1
522daaffb31Sdp	typeset TPATH=$2
523daaffb31Sdp	typeset lhsfile=$3
524daaffb31Sdp	typeset rhsfile=$4
525daaffb31Sdp	typeset comments=$5
5267c478bd9Sstevel@tonic-gate	typeset RTOP
527daaffb31Sdp
5287c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
529daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
530daaffb31Sdp
531daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
532daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
533daaffb31Sdp
534daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
535cac38512Smjnelson	    <script type="text/javascript" src="$RTOP/ancnav.js"></script>
5367c478bd9Sstevel@tonic-gate	    </head>
537daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
538cac38512Smjnelson	    <a name="0"></a>
539cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
540daaffb31Sdp	EOF
541daaffb31Sdp
542daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
543daaffb31Sdp
544daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
545daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
546daaffb31Sdp
547daaffb31Sdp	close='</body></html>'
548daaffb31Sdp
549daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
550daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
551daaffb31Sdp
552daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
553daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
554daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
555daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
556daaffb31Sdp	  <frameset rows="*,60">
557daaffb31Sdp	    <frameset cols="50%,50%">
558cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
559cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
560daaffb31Sdp	    </frameset>
561daaffb31Sdp	  <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
562cac38512Smjnelson	   marginheight="0" name="nav"></frame>
563daaffb31Sdp	  <noframes>
564daaffb31Sdp            <body id="SUNWwebrev">
565daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
5667c478bd9Sstevel@tonic-gate	      and has the feature enabled.
567daaffb31Sdp            </body>
568daaffb31Sdp	  </noframes>
569daaffb31Sdp	  </frameset>
5707c478bd9Sstevel@tonic-gate	</html>
5717c478bd9Sstevel@tonic-gate	EOF
5727c478bd9Sstevel@tonic-gate}
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate
575daaffb31Sdp#
576daaffb31Sdp# fix_postscript
577daaffb31Sdp#
578daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
579daaffb31Sdp# 	- removing all extraneous headers/trailers
580daaffb31Sdp#	- making the page numbers right
581daaffb31Sdp#	- removing pages devoid of contents which confuse some
582daaffb31Sdp#	  postscript readers.
583daaffb31Sdp#
584daaffb31Sdp# From Casper.
585daaffb31Sdp#
586daaffb31Sdpfunction fix_postscript
5877c478bd9Sstevel@tonic-gate{
588daaffb31Sdp	infile=$1
5897c478bd9Sstevel@tonic-gate
590daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
5917c478bd9Sstevel@tonic-gate
592daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
593daaffb31Sdp	print "%%Orientation: Landscape\n";
5947c478bd9Sstevel@tonic-gate
595daaffb31Sdp	$pno = 0;
596daaffb31Sdp	$doprint = 1;
597daaffb31Sdp
598daaffb31Sdp	$page = "";
599daaffb31Sdp
600daaffb31Sdp	while (<>) {
601daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
602daaffb31Sdp
603daaffb31Sdp		if (/^%%Page:/) {
604daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
605daaffb31Sdp				# Header or single page containing text
606daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
607daaffb31Sdp				print $page;
608daaffb31Sdp				$pno++;
609daaffb31Sdp			} else {
610daaffb31Sdp				# Empty page, skip it.
6117c478bd9Sstevel@tonic-gate			}
612daaffb31Sdp			$page = "";
613daaffb31Sdp			$doprint = 1;
6147c478bd9Sstevel@tonic-gate			next;
6157c478bd9Sstevel@tonic-gate		}
6167c478bd9Sstevel@tonic-gate
617daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
618daaffb31Sdp		# %%Page of the next
619daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
620daaffb31Sdp		$page .= $_ if ($doprint);
6217c478bd9Sstevel@tonic-gate	}
6227c478bd9Sstevel@tonic-gate
623daaffb31Sdp	if ($page =~ /\)S/) {
624daaffb31Sdp		print "%%Page: ? $pno\n";
625daaffb31Sdp		print $page;
626daaffb31Sdp	} else {
627daaffb31Sdp		$pno--;
628daaffb31Sdp	}
629daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
630daaffb31SdpEOF
631daaffb31Sdp
63214983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
633daaffb31Sdp}
634daaffb31Sdp
635daaffb31Sdp
636daaffb31Sdp#
637daaffb31Sdp# input_cmd | insert_anchors | output_cmd
638daaffb31Sdp#
6397c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
640daaffb31Sdp# anchors.  These are used to drive the frames version of the
6417c478bd9Sstevel@tonic-gate# sdiffs output.
6427c478bd9Sstevel@tonic-gate#
6437c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
6447c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
6457c478bd9Sstevel@tonic-gate#
646daaffb31Sdp# The script detects changed lines as any line that has a "<span
647daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
648daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
6497c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
6507c478bd9Sstevel@tonic-gate# deleted.
6517c478bd9Sstevel@tonic-gate#
652daaffb31Sdpfunction insert_anchors
653daaffb31Sdp{
654*cdf0c1d5Smjnelson	$AWK '
6557c478bd9Sstevel@tonic-gate	function ia() {
656daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
6577c478bd9Sstevel@tonic-gate	}
658daaffb31Sdp
6597c478bd9Sstevel@tonic-gate	BEGIN {
660daaffb31Sdp		anc=1;
6617c478bd9Sstevel@tonic-gate		inblock=1;
662daaffb31Sdp		printf "<pre>\n";
6637c478bd9Sstevel@tonic-gate	}
664daaffb31Sdp	NF == 0 || /^<span class=/ {
6657c478bd9Sstevel@tonic-gate		if (inblock == 0) {
6667c478bd9Sstevel@tonic-gate			ia();
6677c478bd9Sstevel@tonic-gate			inblock=1;
6687c478bd9Sstevel@tonic-gate		}
6697c478bd9Sstevel@tonic-gate		print;
6707c478bd9Sstevel@tonic-gate		next;
6717c478bd9Sstevel@tonic-gate	}
6727c478bd9Sstevel@tonic-gate	{
6737c478bd9Sstevel@tonic-gate		inblock=0;
6747c478bd9Sstevel@tonic-gate		print;
6757c478bd9Sstevel@tonic-gate	}
6767c478bd9Sstevel@tonic-gate	END {
6777c478bd9Sstevel@tonic-gate		ia();
678daaffb31Sdp
679daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
680daaffb31Sdp		printf "--- EOF ---</b>"
6817c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
682daaffb31Sdp		printf "</pre>"
683daaffb31Sdp		printf "<form name=\"eof\">";
684cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
685cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
686daaffb31Sdp		printf "</form>";
6877c478bd9Sstevel@tonic-gate	}
6887c478bd9Sstevel@tonic-gate	' $1
6897c478bd9Sstevel@tonic-gate}
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate
692daaffb31Sdp#
693daaffb31Sdp# relative_dir
694daaffb31Sdp#
695daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
696daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
697daaffb31Sdp# this function would print "../../../../".
698daaffb31Sdp#
699daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
700daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
701daaffb31Sdp# is not relocatable.
702daaffb31Sdp#
703daaffb31Sdpfunction relative_dir
7047c478bd9Sstevel@tonic-gate{
705daaffb31Sdp	typeset cur="${1##$2?(/)}"
706daaffb31Sdp	typeset ret=""
707daaffb31Sdp	if [[ $2 == $cur ]]; then   # Should never happen.
708daaffb31Sdp		# Should never happen.
70914983201Sdp		print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
710daaffb31Sdp		print -u2 "to \"$2\".  Check input paths.  Framed webrev "
711daaffb31Sdp		print -u2 "will not be relocatable!"
712daaffb31Sdp		print $2
713daaffb31Sdp		return
714daaffb31Sdp	fi
715daaffb31Sdp
716daaffb31Sdp	while [[ -n ${cur} ]];
7177c478bd9Sstevel@tonic-gate	do
7187c478bd9Sstevel@tonic-gate		cur=${cur%%*(/)*([!/])}
719daaffb31Sdp		if [[ -z $ret ]]; then
720daaffb31Sdp			ret=".."
721daaffb31Sdp		else
7227c478bd9Sstevel@tonic-gate			ret="../$ret"
723daaffb31Sdp		fi
7247c478bd9Sstevel@tonic-gate	done
7257c478bd9Sstevel@tonic-gate	print $ret
7267c478bd9Sstevel@tonic-gate}
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate
729daaffb31Sdp#
730daaffb31Sdp# frame_nav_js
731daaffb31Sdp#
732daaffb31Sdp# Emit javascript for frame navigation
733daaffb31Sdp#
734daaffb31Sdpfunction frame_nav_js
7357c478bd9Sstevel@tonic-gate{
7367c478bd9Sstevel@tonic-gatecat << \EOF
7377c478bd9Sstevel@tonic-gatevar myInt;
7387c478bd9Sstevel@tonic-gatevar scrolling=0;
739daaffb31Sdpvar sfactor = 3;
7407c478bd9Sstevel@tonic-gatevar scount=10;
7417c478bd9Sstevel@tonic-gate
7427c478bd9Sstevel@tonic-gatefunction scrollByPix() {
7437c478bd9Sstevel@tonic-gate	if (scount<=0) {
7447c478bd9Sstevel@tonic-gate		sfactor*=1.2;
7457c478bd9Sstevel@tonic-gate		scount=10;
7467c478bd9Sstevel@tonic-gate	}
7477c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
7487c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
7497c478bd9Sstevel@tonic-gate	scount--;
7507c478bd9Sstevel@tonic-gate}
7517c478bd9Sstevel@tonic-gate
752daaffb31Sdpfunction scrollToAnc(num) {
753daaffb31Sdp
754daaffb31Sdp	// Update the value of the anchor in the form which we use as
755daaffb31Sdp	// storage for this value.  setAncValue() will take care of
756daaffb31Sdp	// correcting for overflow and underflow of the value and return
757daaffb31Sdp	// us the new value.
758daaffb31Sdp	num = setAncValue(num);
759daaffb31Sdp
760daaffb31Sdp	// Set location and scroll back a little to expose previous
761daaffb31Sdp	// lines.
762daaffb31Sdp	//
763daaffb31Sdp	// Note that this could be improved: it is possible although
764daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
765daaffb31Sdp	// scroll to that location directly.
766daaffb31Sdp	//
7677c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
7687c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
769daaffb31Sdp
7707c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
7717c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
7727c478bd9Sstevel@tonic-gate}
7737c478bd9Sstevel@tonic-gate
774daaffb31Sdpfunction getAncValue()
775daaffb31Sdp{
776daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
777daaffb31Sdp}
778daaffb31Sdp
779daaffb31Sdpfunction setAncValue(val)
780daaffb31Sdp{
781daaffb31Sdp	if (val <= 0) {
782daaffb31Sdp		val = 0;
783daaffb31Sdp		parent.nav.document.diff.real.value = val;
784daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
785daaffb31Sdp		return (val);
786daaffb31Sdp	}
787daaffb31Sdp
788daaffb31Sdp	//
789daaffb31Sdp	// The way we compute the max anchor value is to stash it
790daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
791daaffb31Sdp	// on each side, so we pluck from the left.
792daaffb31Sdp	//
793daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
794daaffb31Sdp	if (val < maxval) {
795daaffb31Sdp		parent.nav.document.diff.real.value = val;
796daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
797daaffb31Sdp		return (val);
798daaffb31Sdp	}
799daaffb31Sdp
800daaffb31Sdp	// this must be: val >= maxval
801daaffb31Sdp	val = maxval;
802daaffb31Sdp	parent.nav.document.diff.real.value = val;
803daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
804daaffb31Sdp	return (val);
805daaffb31Sdp}
806daaffb31Sdp
8077c478bd9Sstevel@tonic-gatefunction stopScroll() {
8087c478bd9Sstevel@tonic-gate	if (scrolling==1) {
8097c478bd9Sstevel@tonic-gate		clearInterval(myInt);
8107c478bd9Sstevel@tonic-gate		scrolling=0;
8117c478bd9Sstevel@tonic-gate	}
8127c478bd9Sstevel@tonic-gate}
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gatefunction startScroll() {
8157c478bd9Sstevel@tonic-gate	stopScroll();
8167c478bd9Sstevel@tonic-gate	scrolling=1;
8177c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
8187c478bd9Sstevel@tonic-gate}
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gatefunction handlePress(b) {
821daaffb31Sdp
8227c478bd9Sstevel@tonic-gate	switch (b) {
8237c478bd9Sstevel@tonic-gate	    case 1 :
824daaffb31Sdp		scrollToAnc(-1);
8257c478bd9Sstevel@tonic-gate		break;
8267c478bd9Sstevel@tonic-gate	    case 2 :
827daaffb31Sdp		scrollToAnc(getAncValue() - 1);
8287c478bd9Sstevel@tonic-gate		break;
8297c478bd9Sstevel@tonic-gate	    case 3 :
8307c478bd9Sstevel@tonic-gate		sfactor=-3;
8317c478bd9Sstevel@tonic-gate		startScroll();
8327c478bd9Sstevel@tonic-gate		break;
8337c478bd9Sstevel@tonic-gate	    case 4 :
8347c478bd9Sstevel@tonic-gate		sfactor=3;
8357c478bd9Sstevel@tonic-gate		startScroll();
8367c478bd9Sstevel@tonic-gate		break;
8377c478bd9Sstevel@tonic-gate	    case 5 :
838daaffb31Sdp		scrollToAnc(getAncValue() + 1);
8397c478bd9Sstevel@tonic-gate		break;
8407c478bd9Sstevel@tonic-gate	    case 6 :
841daaffb31Sdp		scrollToAnc(999999);
8427c478bd9Sstevel@tonic-gate		break;
8437c478bd9Sstevel@tonic-gate	}
8447c478bd9Sstevel@tonic-gate}
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
8477c478bd9Sstevel@tonic-gate	stopScroll();
8487c478bd9Sstevel@tonic-gate}
8497c478bd9Sstevel@tonic-gate
850daaffb31Sdpfunction keypress(ev) {
851daaffb31Sdp	var keynum;
852daaffb31Sdp	var keychar;
853daaffb31Sdp
854daaffb31Sdp	if (window.event) { // IE
855daaffb31Sdp		keynum = ev.keyCode;
856daaffb31Sdp	} else if (ev.which) { // non-IE
857daaffb31Sdp		keynum = ev.which;
858daaffb31Sdp	}
859daaffb31Sdp
860daaffb31Sdp	keychar = String.fromCharCode(keynum);
861daaffb31Sdp
862daaffb31Sdp	if (keychar == "k") {
863daaffb31Sdp		handlePress(2);
864daaffb31Sdp		return (0);
865daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
866daaffb31Sdp		handlePress(5);
867daaffb31Sdp		return (0);
868daaffb31Sdp	}
869daaffb31Sdp	return (1);
870daaffb31Sdp}
871daaffb31Sdp
8727c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
873daaffb31Sdp	val = parent.nav.document.diff.display.value;
874daaffb31Sdp	if (val == "EOF") {
875daaffb31Sdp		scrollToAnc(999999);
876daaffb31Sdp		return;
877daaffb31Sdp	}
878daaffb31Sdp
879daaffb31Sdp	if (val == "BOF") {
880daaffb31Sdp		scrollToAnc(0);
881daaffb31Sdp		return;
882daaffb31Sdp	}
883daaffb31Sdp
884daaffb31Sdp        i=parseInt(val);
8857c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
886daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
8877c478bd9Sstevel@tonic-gate        } else {
888daaffb31Sdp                scrollToAnc(i);
8897c478bd9Sstevel@tonic-gate        }
8907c478bd9Sstevel@tonic-gate        return false;
8917c478bd9Sstevel@tonic-gate}
8927c478bd9Sstevel@tonic-gate
893daaffb31SdpEOF
894daaffb31Sdp}
895daaffb31Sdp
896daaffb31Sdp#
897daaffb31Sdp# frame_navigation
898daaffb31Sdp#
899daaffb31Sdp# Output anchor navigation file for framed sdiffs.
900daaffb31Sdp#
901daaffb31Sdpfunction frame_navigation
902daaffb31Sdp{
903daaffb31Sdp	print "$HTML<head>$STDHEAD"
904daaffb31Sdp
905daaffb31Sdp	cat << \EOF
906daaffb31Sdp<title>Anchor Navigation</title>
907daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
908daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
909daaffb31Sdp
910daaffb31Sdp<style type="text/css">
911daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
912daaffb31Sdp		    background-color: #eee; text-align: center;
913daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
914daaffb31Sdp    div.button a { font-weight: bold; color: black }
915daaffb31Sdp    div.button td:hover { background: #ffcc99; }
916daaffb31Sdp</style>
917daaffb31SdpEOF
918daaffb31Sdp
919cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
920daaffb31Sdp
921daaffb31Sdp	cat << \EOF
9227c478bd9Sstevel@tonic-gate</head>
923daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
924daaffb31Sdp	onkeypress="keypress(event);">
9257c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
9267c478bd9Sstevel@tonic-gate      <center>
927cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
9287c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
9297c478bd9Sstevel@tonic-gate      </center>
9307c478bd9Sstevel@tonic-gate    </noscript>
9317c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
932daaffb31Sdp	<tr>
933daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
934daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
935daaffb31Sdp          at right</td>
936daaffb31Sdp	  <td align="center" valign="top" width="50%">
9377c478bd9Sstevel@tonic-gate	    <div class="button">
938daaffb31Sdp	      <table border="0" align="center">
939daaffb31Sdp                  <tr>
940daaffb31Sdp		    <td>
9417c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
9427c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
9437c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
9447c478bd9Sstevel@tonic-gate			 onClick="return false;"
9457c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
946daaffb31Sdp		    <td>
9477c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
9487c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
9497c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
9507c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
951daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
952daaffb31Sdp		    <td>
9537c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
9547c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
9557c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
9567c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
9577c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
9587c478bd9Sstevel@tonic-gate		    </td></tr>
959daaffb31Sdp
9607c478bd9Sstevel@tonic-gate		  <tr>
961daaffb31Sdp		    <td>
9627c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
9637c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
9647c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
9657c478bd9Sstevel@tonic-gate			 onClick="return false;"
9667c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
967daaffb31Sdp		    <td>
9687c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
9697c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
9707c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
9717c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
972daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
973daaffb31Sdp		    <td>
9747c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
9757c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
9767c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
9777c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
9787c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
979daaffb31Sdp		  </tr>
980daaffb31Sdp              </table>
981daaffb31Sdp	    </div>
982daaffb31Sdp	  </td>
9837c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
984daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
985cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
986cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
9877c478bd9Sstevel@tonic-gate	    </form>
9887c478bd9Sstevel@tonic-gate	  </th>
989daaffb31Sdp	</tr>
9907c478bd9Sstevel@tonic-gate    </table>
9917c478bd9Sstevel@tonic-gate  </body>
9927c478bd9Sstevel@tonic-gate</html>
9937c478bd9Sstevel@tonic-gateEOF
9947c478bd9Sstevel@tonic-gate}
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate
997daaffb31Sdp
998daaffb31Sdp#
999daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1000daaffb31Sdp#
1001daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1002daaffb31Sdp# context or unified diffs.
1003daaffb31Sdp#
10047c478bd9Sstevel@tonic-gatediff_to_html()
10057c478bd9Sstevel@tonic-gate{
10067c478bd9Sstevel@tonic-gate	TNAME=$1
1007daaffb31Sdp	TPATH=$2
1008daaffb31Sdp	DIFFTYPE=$3
1009daaffb31Sdp	COMMENT=$4
1010daaffb31Sdp
1011daaffb31Sdp	print "$HTML<head>$STDHEAD"
1012daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1013daaffb31Sdp
1014daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1015daaffb31Sdp		print "$UDIFFCSS"
1016daaffb31Sdp	fi
1017daaffb31Sdp
1018daaffb31Sdp	cat <<-EOF
1019daaffb31Sdp	</head>
1020daaffb31Sdp	<body id="SUNWwebrev">
1021daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1022daaffb31Sdp	<pre>$COMMENT</pre>
1023daaffb31Sdp        <pre>
1024daaffb31Sdp	EOF
10257c478bd9Sstevel@tonic-gate
1026*cdf0c1d5Smjnelson	html_quote | $AWK '
1027daaffb31Sdp	/^--- new/	{ next }
1028daaffb31Sdp	/^\+\+\+ new/	{ next }
1029daaffb31Sdp	/^--- old/	{ next }
1030daaffb31Sdp	/^\*\*\* old/	{ next }
1031daaffb31Sdp	/^\*\*\*\*/	{ next }
10327c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1033cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1034daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1035daaffb31Sdp			  next}
1036daaffb31Sdp
1037cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1038daaffb31Sdp			  next}
1039daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1040daaffb31Sdp			  next}
1041daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1042daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1043daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1044daaffb31Sdp			{printf "%s\n", $0; next}
10457c478bd9Sstevel@tonic-gate	'
1046daaffb31Sdp
1047daaffb31Sdp	print "</pre></body></html>\n"
10487c478bd9Sstevel@tonic-gate}
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate
1051daaffb31Sdp#
1052daaffb31Sdp# source_to_html { new | old } <filename>
1053daaffb31Sdp#
1054daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1055daaffb31Sdp#
10567c478bd9Sstevel@tonic-gatesource_to_html()
10577c478bd9Sstevel@tonic-gate{
10587c478bd9Sstevel@tonic-gate	WHICH=$1
10597c478bd9Sstevel@tonic-gate	TNAME=$2
10607c478bd9Sstevel@tonic-gate
1061daaffb31Sdp	print "$HTML<head>$STDHEAD"
1062*cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1063daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1064daaffb31Sdp	print "<pre>"
1065*cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1066daaffb31Sdp	print "</pre></body></html>"
10677c478bd9Sstevel@tonic-gate}
10687c478bd9Sstevel@tonic-gate
1069daaffb31Sdp#
1070*cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1071daaffb31Sdp#
1072daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1073daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1074daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1075daaffb31Sdp# delta in that list (the first delta unique to the child).
10767c478bd9Sstevel@tonic-gate#
10777c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1078daaffb31Sdp#
1079daaffb31Sdpcomments_from_teamware()
10807c478bd9Sstevel@tonic-gate{
1081daaffb31Sdp	fmt=$1
1082daaffb31Sdp	pfile=$PWS/$2
1083daaffb31Sdp	cfile=$CWS/$3
10847c478bd9Sstevel@tonic-gate
1085*cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1086*cdf0c1d5Smjnelson		pfile=$RWS/$2
1087*cdf0c1d5Smjnelson	fi
1088*cdf0c1d5Smjnelson
1089daaffb31Sdp	if [[ -f $pfile ]]; then
1090*cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
10917c478bd9Sstevel@tonic-gate	else
10927c478bd9Sstevel@tonic-gate		psid=1.1
10937c478bd9Sstevel@tonic-gate	fi
10947c478bd9Sstevel@tonic-gate
1095*cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
10967c478bd9Sstevel@tonic-gate	N=${#sids[@]}
10977c478bd9Sstevel@tonic-gate
1098daaffb31Sdp	nawkprg='
1099daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1100daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1101daaffb31Sdp		NF == 0u	{ continue }
1102daaffb31Sdp		{if (p==0) continue; print $0 }'
1103daaffb31Sdp
11047c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
11057c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
11067c478bd9Sstevel@tonic-gate
1107daaffb31Sdp		if [[ $fmt == "text" ]]; then
1108*cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1109*cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1110daaffb31Sdp			return
1111daaffb31Sdp		fi
1112daaffb31Sdp
1113*cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1114*cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
11157c478bd9Sstevel@tonic-gate	fi
11167c478bd9Sstevel@tonic-gate}
11177c478bd9Sstevel@tonic-gate
1118daaffb31Sdp#
1119*cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1120daaffb31Sdp#
1121*cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1122*cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1123*cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1124*cdf0c1d5Smjnelson# are turned into URLs.
1125*cdf0c1d5Smjnelson#
1126*cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1127daaffb31Sdp#
1128daaffb31Sdpcomments_from_wx()
11297c478bd9Sstevel@tonic-gate{
1130daaffb31Sdp	typeset fmt=$1
1131daaffb31Sdp	typeset p=$2
11327c478bd9Sstevel@tonic-gate
1133*cdf0c1d5Smjnelson	comm=`$AWK '
1134daaffb31Sdp	$1 == "'$p'" {
11357c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
11367c478bd9Sstevel@tonic-gate		getline
11377c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
11387c478bd9Sstevel@tonic-gate		exit
1139daaffb31Sdp	}' < $wxfile`
1140daaffb31Sdp
1141*cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1142*cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1143*cdf0c1d5Smjnelson	fi
1144*cdf0c1d5Smjnelson
1145daaffb31Sdp	if [[ $fmt == "text" ]]; then
1146*cdf0c1d5Smjnelson		print -- "$comm"
1147daaffb31Sdp		return
1148daaffb31Sdp	fi
1149daaffb31Sdp
1150*cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1151*cdf0c1d5Smjnelson
11527c478bd9Sstevel@tonic-gate}
11537c478bd9Sstevel@tonic-gate
11547c478bd9Sstevel@tonic-gate#
1155daaffb31Sdp# getcomments {text|html} filepath parentpath
1156daaffb31Sdp#
1157daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1158daaffb31Sdp#
1159daaffb31Sdpgetcomments()
1160daaffb31Sdp{
1161daaffb31Sdp	typeset fmt=$1
1162daaffb31Sdp	typeset p=$2
1163daaffb31Sdp	typeset pp=$3
11647c478bd9Sstevel@tonic-gate
1165*cdf0c1d5Smjnelson	#
1166*cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1167*cdf0c1d5Smjnelson	# will be used there, too
1168*cdf0c1d5Smjnelson	#
1169daaffb31Sdp	if [[ -n $wxfile ]]; then
1170daaffb31Sdp		comments_from_wx $fmt $p
1171daaffb31Sdp	else
1172daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1173daaffb31Sdp			comments_from_teamware $fmt $pp $p
1174daaffb31Sdp		fi
1175daaffb31Sdp	fi
1176daaffb31Sdp}
1177daaffb31Sdp
1178daaffb31Sdp#
1179daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1180daaffb31Sdp#
1181daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1182daaffb31Sdp#
1183daaffb31Sdpfunction printCI
1184daaffb31Sdp{
1185daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1186daaffb31Sdp	typeset str
1187daaffb31Sdp	if (( tot == 1 )); then
1188daaffb31Sdp		str="line"
1189daaffb31Sdp	else
1190daaffb31Sdp		str="lines"
1191daaffb31Sdp	fi
1192daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1193daaffb31Sdp	    $tot $str $ins $del $mod $unc
1194daaffb31Sdp}
1195daaffb31Sdp
1196daaffb31Sdp
1197daaffb31Sdp#
1198daaffb31Sdp# difflines <oldfile> <newfile>
1199daaffb31Sdp#
1200daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1201daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1202daaffb31Sdp#
12037c478bd9Sstevel@tonic-gatefunction difflines
12047c478bd9Sstevel@tonic-gate{
1205daaffb31Sdp	integer tot mod del ins unc err
12067c478bd9Sstevel@tonic-gate	typeset filename
12077c478bd9Sstevel@tonic-gate
1208*cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1209daaffb31Sdp	# Change range of lines: N,Nc
12107c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
12117c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
12127c478bd9Sstevel@tonic-gate		if (n != 2) {
12137c478bd9Sstevel@tonic-gate		    error=2
12147c478bd9Sstevel@tonic-gate		    exit;
12157c478bd9Sstevel@tonic-gate		}
1216daaffb31Sdp		#
1217daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1218daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1219daaffb31Sdp		#
12207c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1221daaffb31Sdp
1222daaffb31Sdp		#
1223daaffb31Sdp		# Now count replacement lines: each represents a change instead
1224daaffb31Sdp		# of a delete, so increment c and decrement r.
1225daaffb31Sdp		#
12267c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
12277c478bd9Sstevel@tonic-gate			c++;
12287c478bd9Sstevel@tonic-gate			r--;
12297c478bd9Sstevel@tonic-gate		}
1230daaffb31Sdp		#
1231daaffb31Sdp		# If there were more replacement lines than original lines,
1232daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1233daaffb31Sdp		# but there are r changes that should be counted as adds, and
1234daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1235daaffb31Sdp		#
12367c478bd9Sstevel@tonic-gate		if (r < 0) {
12377c478bd9Sstevel@tonic-gate			a-=r;
12387c478bd9Sstevel@tonic-gate			c+=r;
12397c478bd9Sstevel@tonic-gate		}
1240daaffb31Sdp
1241daaffb31Sdp		#
1242daaffb31Sdp		# If there were more original lines than replacement lines, then
1243daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1244daaffb31Sdp		#
12457c478bd9Sstevel@tonic-gate		if (r > 0) {
12467c478bd9Sstevel@tonic-gate			d+=r;
12477c478bd9Sstevel@tonic-gate		}
12487c478bd9Sstevel@tonic-gate		next;
12497c478bd9Sstevel@tonic-gate	}
12507c478bd9Sstevel@tonic-gate
1251daaffb31Sdp	# Change lines: Nc
12527c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1253daaffb31Sdp		# The first line is a replacement; any more are additions.
12547c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
12557c478bd9Sstevel@tonic-gate			c++;
12567c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
12577c478bd9Sstevel@tonic-gate		}
12587c478bd9Sstevel@tonic-gate		next;
12597c478bd9Sstevel@tonic-gate	}
12607c478bd9Sstevel@tonic-gate
1261daaffb31Sdp	# Add lines: both Na and N,Na
12627c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
12637c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
12647c478bd9Sstevel@tonic-gate		next;
12657c478bd9Sstevel@tonic-gate	}
12667c478bd9Sstevel@tonic-gate
1267daaffb31Sdp	# Delete range of lines: N,Nd
12687c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
12697c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
12707c478bd9Sstevel@tonic-gate		if (n != 2) {
12717c478bd9Sstevel@tonic-gate			error=2
12727c478bd9Sstevel@tonic-gate			exit;
12737c478bd9Sstevel@tonic-gate		}
1274daaffb31Sdp		#
1275daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1276daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1277daaffb31Sdp		#
12787c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
12797c478bd9Sstevel@tonic-gate		d+=r;
12807c478bd9Sstevel@tonic-gate		next;
12817c478bd9Sstevel@tonic-gate	}
12827c478bd9Sstevel@tonic-gate
1283daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
12847c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
12857c478bd9Sstevel@tonic-gate
1286daaffb31Sdp	# Should not get here!
12877c478bd9Sstevel@tonic-gate	{
12887c478bd9Sstevel@tonic-gate		error=1;
12897c478bd9Sstevel@tonic-gate		exit;
12907c478bd9Sstevel@tonic-gate	}
12917c478bd9Sstevel@tonic-gate
1292daaffb31Sdp	# Finish off - print results
12937c478bd9Sstevel@tonic-gate	END {
1294daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
12957c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
12967c478bd9Sstevel@tonic-gate	}' )
12977c478bd9Sstevel@tonic-gate
1298*cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
12997c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1300daaffb31Sdp		print "Unexpected Error occurred reading" \
1301daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1302daaffb31Sdp		return
1303daaffb31Sdp	fi
1304daaffb31Sdp
13057c478bd9Sstevel@tonic-gate	# Accumulate totals
13067c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1307daaffb31Sdp	(( TMOD += mod ))
13087c478bd9Sstevel@tonic-gate	(( TDEL += del ))
13097c478bd9Sstevel@tonic-gate	(( TINS += ins ))
13107c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1311*cdf0c1d5Smjnelson	unc=`wc -l < $1`
13127c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1313daaffb31Sdp		(( unc -= del + mod ))
13147c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
13157c478bd9Sstevel@tonic-gate	fi
13167c478bd9Sstevel@tonic-gate	# print summary
1317daaffb31Sdp	print "<span class=\"lineschanged\">"
1318daaffb31Sdp	printCI $tot $ins $del $mod $unc
1319daaffb31Sdp	print "</span>"
13207c478bd9Sstevel@tonic-gate}
13217c478bd9Sstevel@tonic-gate
1322daaffb31Sdp
13237c478bd9Sstevel@tonic-gate#
1324daaffb31Sdp# flist_from_wx
1325daaffb31Sdp#
1326daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1327daaffb31Sdp# Sets the global 'wxfile' variable.
1328daaffb31Sdp#
1329daaffb31Sdpfunction flist_from_wx
13307c478bd9Sstevel@tonic-gate{
1331daaffb31Sdp	typeset argfile=$1
1332daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1333daaffb31Sdp		#
1334daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1335daaffb31Sdp		# because the webrev does a "cd" later on.
1336daaffb31Sdp		#
1337daaffb31Sdp		wxfile=$PWD/$argfile
13387c478bd9Sstevel@tonic-gate	else
1339daaffb31Sdp		wxfile=$argfile
13407c478bd9Sstevel@tonic-gate	fi
13417c478bd9Sstevel@tonic-gate
1342*cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
13437c478bd9Sstevel@tonic-gate	  while (getline) {
13447c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
13457c478bd9Sstevel@tonic-gate		if (c > 0) print
13467c478bd9Sstevel@tonic-gate	  }
1347daaffb31Sdp	}' $wxfile > $FLIST
13487c478bd9Sstevel@tonic-gate
1349daaffb31Sdp	print " Done."
1350daaffb31Sdp}
13517c478bd9Sstevel@tonic-gate
1352daaffb31Sdp#
1353daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1354daaffb31Sdp#
1355daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1356daaffb31Sdp# names may come from the "update/create" messages and others from the
1357daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1358daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1359daaffb31Sdp# -n as well, but remove them if they are already defined.
1360daaffb31Sdp#
1361daaffb31Sdpfunction flist_from_teamware
1362daaffb31Sdp{
1363*cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1364daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1365daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1366daaffb31Sdp			    "valid teamware workspace"
13677c478bd9Sstevel@tonic-gate			exit 1
13687c478bd9Sstevel@tonic-gate		fi
1369daaffb31Sdp		parent_args="-p $codemgr_parent"
13707c478bd9Sstevel@tonic-gate	fi
13717c478bd9Sstevel@tonic-gate
1372daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
13737c478bd9Sstevel@tonic-gate
1374daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1375*cdf0c1d5Smjnelson	    $AWK '
1376daaffb31Sdp		/^update:|^create:/	{print $2}
1377daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1378daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1379daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1380daaffb31Sdp		NF == 0			{p=0 ; continue}
1381daaffb31Sdp		/^rename/		{old=$3}
1382daaffb31Sdp		$1 == "to:"		{print $2, old}
1383daaffb31Sdp		/^"/			{continue}
1384daaffb31Sdp		p == 1			{print $1}' |
1385daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
13867c478bd9Sstevel@tonic-gate
1387daaffb31Sdp	print " Done."
1388daaffb31Sdp}
1389daaffb31Sdp
1390*cdf0c1d5Smjnelson#
1391*cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1392*cdf0c1d5Smjnelson#
1393*cdf0c1d5Smjnelsonfunction hg_active_wxfile
1394*cdf0c1d5Smjnelson{
1395*cdf0c1d5Smjnelson	typeset child=$1
1396*cdf0c1d5Smjnelson	typeset parent=$2
1397*cdf0c1d5Smjnelson
1398*cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
1399*cdf0c1d5Smjnelson	$HG_ACTIVE -w $child -p $parent > $TMPFLIST
1400*cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1401*cdf0c1d5Smjnelson}
1402*cdf0c1d5Smjnelson
1403*cdf0c1d5Smjnelson#
1404*cdf0c1d5Smjnelson# flist_from_mercurial
1405*cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1406*cdf0c1d5Smjnelson# flist_from_wx
1407*cdf0c1d5Smjnelson#
1408*cdf0c1d5Smjnelsonfunction flist_from_mercurial
1409*cdf0c1d5Smjnelson{
1410*cdf0c1d5Smjnelson	typeset child=$1
1411*cdf0c1d5Smjnelson	typeset parent=$2
1412*cdf0c1d5Smjnelson
1413*cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1414*cdf0c1d5Smjnelson
1415*cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1416*cdf0c1d5Smjnelson		print		# Blank line for the \c above
1417*cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1418*cdf0c1d5Smjnelson		exit 1
1419*cdf0c1d5Smjnelson	fi
1420*cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1421*cdf0c1d5Smjnelson
1422*cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1423*cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1424*cdf0c1d5Smjnelson}
1425*cdf0c1d5Smjnelson
1426*cdf0c1d5Smjnelson#
1427*cdf0c1d5Smjnelson# flist_from_subversion
1428*cdf0c1d5Smjnelson#
1429*cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1430*cdf0c1d5Smjnelson#
1431*cdf0c1d5Smjnelsonfunction flist_from_subversion
1432*cdf0c1d5Smjnelson{
1433*cdf0c1d5Smjnelson	CWS=$1
1434*cdf0c1d5Smjnelson	OLDPWD=$2
1435*cdf0c1d5Smjnelson
1436*cdf0c1d5Smjnelson	cd $CWS
1437*cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1438*cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1439*cdf0c1d5Smjnelson	print -u2 " Done."
1440*cdf0c1d5Smjnelson	cd $OLDPWD
1441*cdf0c1d5Smjnelson}
1442*cdf0c1d5Smjnelson
1443daaffb31Sdpfunction env_from_flist
1444daaffb31Sdp{
1445daaffb31Sdp	[[ -r $FLIST ]] || return
1446daaffb31Sdp
1447daaffb31Sdp	#
1448daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1449daaffb31Sdp	# list.  Then copy those into our local versions of those
1450daaffb31Sdp	# variables if they have not been set already.
1451daaffb31Sdp	#
14527c478bd9Sstevel@tonic-gate	eval `sed -e "s/#.*$//" $FLIST | grep = `
14537c478bd9Sstevel@tonic-gate
1454*cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1455*cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1456*cdf0c1d5Smjnelson		export CODEMGR_WS
1457*cdf0c1d5Smjnelson	fi
14587c478bd9Sstevel@tonic-gate
1459daaffb31Sdp	#
1460daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1461daaffb31Sdp	#
1462*cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1463daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1464*cdf0c1d5Smjnelson		export CODEMGR_PARENT
1465daaffb31Sdp	fi
1466daaffb31Sdp}
1467daaffb31Sdp
146814983201Sdpfunction look_for_prog
146914983201Sdp{
147014983201Sdp	typeset path
147114983201Sdp	typeset ppath
147214983201Sdp	typeset progname=$1
147314983201Sdp
147414983201Sdp	ppath=$PATH
147514983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
147614983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1477*cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
147814983201Sdp
147914983201Sdp	PATH=$ppath prog=`whence $progname`
148014983201Sdp	if [[ -n $prog ]]; then
148114983201Sdp		print $prog
148214983201Sdp	fi
148314983201Sdp}
148414983201Sdp
1485*cdf0c1d5Smjnelsonfunction get_file_mode
1486*cdf0c1d5Smjnelson{
1487*cdf0c1d5Smjnelson	$PERL -e '
1488*cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1489*cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1490*cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1491*cdf0c1d5Smjnelson			exit 0;
1492*cdf0c1d5Smjnelson		} else {
1493*cdf0c1d5Smjnelson			exit 1;
1494*cdf0c1d5Smjnelson		}
1495*cdf0c1d5Smjnelson	    ' $1
1496*cdf0c1d5Smjnelson}
1497*cdf0c1d5Smjnelson
1498*cdf0c1d5Smjnelsonfunction build_old_new_teamware
1499*cdf0c1d5Smjnelson{
1500*cdf0c1d5Smjnelson	typeset olddir="$1"
1501*cdf0c1d5Smjnelson	typeset newdir="$2"
1502*cdf0c1d5Smjnelson
1503*cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1504*cdf0c1d5Smjnelson	# get a readonly copy.
1505*cdf0c1d5Smjnelson
1506*cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1507*cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1508*cdf0c1d5Smjnelson	fi
1509*cdf0c1d5Smjnelson
1510*cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1511*cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1512*cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1513*cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1514*cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1515*cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1516*cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1517*cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1518*cdf0c1d5Smjnelson	# permissions that would result after check in.
1519*cdf0c1d5Smjnelson
1520*cdf0c1d5Smjnelson	#
1521*cdf0c1d5Smjnelson	# Snag new version of file.
1522*cdf0c1d5Smjnelson	#
1523*cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1524*cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1525*cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1526*cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1527*cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1528*cdf0c1d5Smjnelson	fi
1529*cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1530*cdf0c1d5Smjnelson
1531*cdf0c1d5Smjnelson	#
1532*cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1533*cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1534*cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1535*cdf0c1d5Smjnelson	#
1536*cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1537*cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1538*cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1539*cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1540*cdf0c1d5Smjnelson		# the old file.
1541*cdf0c1d5Smjnelson
1542*cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1543*cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1544*cdf0c1d5Smjnelson	else
1545*cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1546*cdf0c1d5Smjnelson			real_parent=$PWS
1547*cdf0c1d5Smjnelson		else
1548*cdf0c1d5Smjnelson			real_parent=$RWS
1549*cdf0c1d5Smjnelson		fi
1550*cdf0c1d5Smjnelson
1551*cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1552*cdf0c1d5Smjnelson
1553*cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1554*cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1555*cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1556*cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1557*cdf0c1d5Smjnelson			else
1558*cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1559*cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1560*cdf0c1d5Smjnelson			fi
1561*cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1562*cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1563*cdf0c1d5Smjnelson		fi
1564*cdf0c1d5Smjnelson	fi
1565*cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1566*cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1567*cdf0c1d5Smjnelson	fi
1568*cdf0c1d5Smjnelson}
1569*cdf0c1d5Smjnelson
1570*cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1571*cdf0c1d5Smjnelson{
1572*cdf0c1d5Smjnelson	typeset olddir="$1"
1573*cdf0c1d5Smjnelson	typeset newdir="$2"
1574*cdf0c1d5Smjnelson	typeset old_mode=
1575*cdf0c1d5Smjnelson	typeset new_mode=
1576*cdf0c1d5Smjnelson	typeset file
1577*cdf0c1d5Smjnelson
1578*cdf0c1d5Smjnelson	#
1579*cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1580*cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1581*cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1582*cdf0c1d5Smjnelson	#
1583*cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1584*cdf0c1d5Smjnelson		file="$PF"
1585*cdf0c1d5Smjnelson	else
1586*cdf0c1d5Smjnelson		file="$PDIR/$PF"
1587*cdf0c1d5Smjnelson	fi
1588*cdf0c1d5Smjnelson	file=`echo $file | sed 's#/#\\\/#g'`
1589*cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1590*cdf0c1d5Smjnelson	old_mode=`sed -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1591*cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1592*cdf0c1d5Smjnelson
1593*cdf0c1d5Smjnelson	#
1594*cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1595*cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1596*cdf0c1d5Smjnelson	#
1597*cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1598*cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1599*cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1600*cdf0c1d5Smjnelson			new_mode=755
1601*cdf0c1d5Smjnelson		else
1602*cdf0c1d5Smjnelson			new_mode=644
1603*cdf0c1d5Smjnelson		fi
1604*cdf0c1d5Smjnelson	fi
1605*cdf0c1d5Smjnelson
1606*cdf0c1d5Smjnelson	#
1607*cdf0c1d5Smjnelson	# new version of the file.
1608*cdf0c1d5Smjnelson	#
1609*cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1610*cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1611*cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1612*cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1613*cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1614*cdf0c1d5Smjnelson		else
1615*cdf0c1d5Smjnelson			# should never happen
1616*cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1617*cdf0c1d5Smjnelson		fi
1618*cdf0c1d5Smjnelson	fi
1619*cdf0c1d5Smjnelson
1620*cdf0c1d5Smjnelson	#
1621*cdf0c1d5Smjnelson	# parent's version of the file
1622*cdf0c1d5Smjnelson	#
1623*cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1624*cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1625*cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1626*cdf0c1d5Smjnelson	#
1627*cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1628*cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1629*cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1630*cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1631*cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1632*cdf0c1d5Smjnelson
1633*cdf0c1d5Smjnelson		if [ $? -ne 0 ]; then
1634*cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1635*cdf0c1d5Smjnelson		else
1636*cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1637*cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1638*cdf0c1d5Smjnelson			else
1639*cdf0c1d5Smjnelson				# should never happen
1640*cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1641*cdf0c1d5Smjnelson			fi
1642*cdf0c1d5Smjnelson		fi
1643*cdf0c1d5Smjnelson	fi
1644*cdf0c1d5Smjnelson}
1645*cdf0c1d5Smjnelson
1646*cdf0c1d5Smjnelsonfunction build_old_new_subversion
1647*cdf0c1d5Smjnelson{
1648*cdf0c1d5Smjnelson	typeset olddir="$1"
1649*cdf0c1d5Smjnelson	typeset newdir="$2"
1650*cdf0c1d5Smjnelson
1651*cdf0c1d5Smjnelson	# Snag new version of file.
1652*cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1653*cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1654*cdf0c1d5Smjnelson
1655*cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1656*cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1657*cdf0c1d5Smjnelson	else
1658*cdf0c1d5Smjnelson		# Get the parent's version of the file.
1659*cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
1660*cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
1661*cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
1662*cdf0c1d5Smjnelson		fi
1663*cdf0c1d5Smjnelson	fi
1664*cdf0c1d5Smjnelson}
1665*cdf0c1d5Smjnelson
1666*cdf0c1d5Smjnelsonfunction build_old_new_unknown
1667*cdf0c1d5Smjnelson{
1668*cdf0c1d5Smjnelson	typeset olddir="$1"
1669*cdf0c1d5Smjnelson	typeset newdir="$2"
1670*cdf0c1d5Smjnelson
1671*cdf0c1d5Smjnelson	#
1672*cdf0c1d5Smjnelson	# Snag new version of file.
1673*cdf0c1d5Smjnelson	#
1674*cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1675*cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1676*cdf0c1d5Smjnelson
1677*cdf0c1d5Smjnelson	#
1678*cdf0c1d5Smjnelson	# Snag the parent's version of the file.
1679*cdf0c1d5Smjnelson	#
1680*cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
1681*cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1682*cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1683*cdf0c1d5Smjnelson	fi
1684*cdf0c1d5Smjnelson}
1685*cdf0c1d5Smjnelson
1686*cdf0c1d5Smjnelsonfunction build_old_new
1687*cdf0c1d5Smjnelson{
1688*cdf0c1d5Smjnelson	typeset WDIR=$1
1689*cdf0c1d5Smjnelson	typeset PWS=$2
1690*cdf0c1d5Smjnelson	typeset PDIR=$3
1691*cdf0c1d5Smjnelson	typeset PF=$4
1692*cdf0c1d5Smjnelson	typeset CWS=$5
1693*cdf0c1d5Smjnelson	typeset DIR=$6
1694*cdf0c1d5Smjnelson	typeset F=$7
1695*cdf0c1d5Smjnelson
1696*cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
1697*cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
1698*cdf0c1d5Smjnelson
1699*cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
1700*cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
1701*cdf0c1d5Smjnelson
1702*cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1703*cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
1704*cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
1705*cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
1706*cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
1707*cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
1708*cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
1709*cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
1710*cdf0c1d5Smjnelson	fi
1711*cdf0c1d5Smjnelson
1712*cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
1713*cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
1714*cdf0c1d5Smjnelson		return 1
1715*cdf0c1d5Smjnelson	fi
1716*cdf0c1d5Smjnelson	return 0
1717*cdf0c1d5Smjnelson}
1718*cdf0c1d5Smjnelson
1719*cdf0c1d5Smjnelson
1720daaffb31Sdp#
1721daaffb31Sdp# Usage message.
1722daaffb31Sdp#
1723daaffb31Sdpfunction usage
1724daaffb31Sdp{
1725daaffb31Sdp	print 'Usage:\twebrev [common-options]
1726daaffb31Sdp	webrev [common-options] ( <file> | - )
1727daaffb31Sdp	webrev [common-options] -w <wx file>
1728daaffb31Sdp
1729daaffb31SdpOptions:
1730daaffb31Sdp	-O: Print bugids/arc cases suitable for OpenSolaris.
1731daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
1732daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
1733daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
1734daaffb31Sdp	-w <wxfile>: Use specified wx active file.
1735daaffb31Sdp
1736daaffb31SdpEnvironment:
1737daaffb31Sdp	WDIR: Control the output directory.
1738daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
1739daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
1740daaffb31Sdp
1741*cdf0c1d5SmjnelsonSCM Specific Options:
1742*cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
1743*cdf0c1d5Smjnelson
1744daaffb31SdpSCM Environment:
1745*cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
1746*cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
1747daaffb31Sdp'
1748daaffb31Sdp
1749daaffb31Sdp	exit 2
1750daaffb31Sdp}
1751daaffb31Sdp
1752daaffb31Sdp#
1753daaffb31Sdp#
1754daaffb31Sdp# Main program starts here
1755daaffb31Sdp#
1756daaffb31Sdp#
1757daaffb31Sdp
1758daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1759daaffb31Sdp
1760daaffb31Sdpset +o noclobber
1761daaffb31Sdp
1762*cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
1763*cdf0c1d5Smjnelson
176414983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
176514983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
1766*cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
1767*cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
176814983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
176914983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
177014983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
1771*cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
1772*cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
1773*cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
1774*cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
1775*cdf0c1d5Smjnelson
177614983201Sdp
177714983201Sdpif [[ ! -x $PERL ]]; then
177814983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
177914983201Sdp	exit 1
1780daaffb31Sdpfi
178114983201Sdp
1782*cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
1783*cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
1784*cdf0c1d5Smjnelson	exit 1
1785*cdf0c1d5Smjnelsonfi
1786*cdf0c1d5Smjnelson
178714983201Sdp#
178814983201Sdp# These aren't fatal, but we want to note them to the user.
178914983201Sdp# We don't warn on the absence of 'wx' until later when we've
179014983201Sdp# determined that we actually need to try to invoke it.
179114983201Sdp#
179214983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
179314983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
179414983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
1795daaffb31Sdp
1796daaffb31Sdp# Declare global total counters.
1797daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
1798daaffb31Sdp
179914983201Sdpflist_mode=
180014983201Sdpflist_file=
1801daaffb31Sdpiflag=
1802daaffb31Sdpoflag=
1803daaffb31Sdppflag=
1804daaffb31Sdplflag=
1805daaffb31Sdpwflag=
1806daaffb31SdpOflag=
1807daaffb31Sdpwhile getopts "i:o:p:lwO" opt
1808daaffb31Sdpdo
1809daaffb31Sdp	case $opt in
1810daaffb31Sdp	i)	iflag=1
1811daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
1812daaffb31Sdp
1813daaffb31Sdp	o)	oflag=1
1814daaffb31Sdp		WDIR=$OPTARG;;
1815daaffb31Sdp
1816daaffb31Sdp	p)	pflag=1
1817daaffb31Sdp		codemgr_parent=$OPTARG;;
1818daaffb31Sdp
1819daaffb31Sdp	#
1820daaffb31Sdp	# If -l has been specified, we need to abort further options
1821daaffb31Sdp	# processing, because subsequent arguments are going to be
1822daaffb31Sdp	# arguments to 'putback -n'.
1823daaffb31Sdp	#
1824daaffb31Sdp	l)	lflag=1
1825daaffb31Sdp		break;;
1826daaffb31Sdp
1827daaffb31Sdp	w)	wflag=1;;
1828daaffb31Sdp
1829daaffb31Sdp	O)	Oflag=1;;
1830daaffb31Sdp
1831daaffb31Sdp	?)	usage;;
1832daaffb31Sdp	esac
1833daaffb31Sdpdone
1834daaffb31Sdp
1835daaffb31SdpFLIST=/tmp/$$.flist
1836daaffb31Sdp
1837daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
1838daaffb31Sdp	usage
1839daaffb31Sdpfi
1840daaffb31Sdp
1841daaffb31Sdp#
1842daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
1843daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
1844daaffb31Sdp#
1845daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
1846daaffb31Sdp	parent_webrev="$codemgr_parent"
1847daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
1848daaffb31Sdpfi
1849daaffb31Sdp
1850daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
1851daaffb31Sdp	shift $(($OPTIND - 1))
1852daaffb31Sdp
1853daaffb31Sdp	if [[ $1 == "-" ]]; then
1854daaffb31Sdp		cat > $FLIST
185514983201Sdp		flist_mode="stdin"
185614983201Sdp		flist_done=1
185714983201Sdp		shift
1858daaffb31Sdp	elif [[ -n $1 ]]; then
185914983201Sdp		if [[ ! -r $1 ]]; then
1860daaffb31Sdp			print -u2 "$1: no such file or not readable"
1861daaffb31Sdp			usage
1862daaffb31Sdp		fi
1863daaffb31Sdp		cat $1 > $FLIST
186414983201Sdp		flist_mode="file"
186514983201Sdp		flist_file=$1
186614983201Sdp		flist_done=1
186714983201Sdp		shift
1868daaffb31Sdp	else
186914983201Sdp		flist_mode="auto"
1870daaffb31Sdp	fi
1871daaffb31Sdpfi
1872daaffb31Sdp
1873daaffb31Sdp#
1874daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
1875daaffb31Sdp# is in use.
1876daaffb31Sdp#
1877*cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
1878*cdf0c1d5Smjnelsoncase "$SCM_MODE" in
1879*cdf0c1d5Smjnelsonteamware|mercurial|subversion)
1880*cdf0c1d5Smjnelson	;;
1881*cdf0c1d5Smjnelsonunknown)
1882*cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
1883*cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
1884*cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
18857c478bd9Sstevel@tonic-gate		exit 1
18867c478bd9Sstevel@tonic-gate	fi
1887*cdf0c1d5Smjnelson	;;
1888*cdf0c1d5Smjnelson*)
1889*cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
1890*cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
1891*cdf0c1d5Smjnelson		exit 1
1892*cdf0c1d5Smjnelson	fi
1893*cdf0c1d5Smjnelson	;;
1894*cdf0c1d5Smjnelsonesac
18957c478bd9Sstevel@tonic-gate
1896daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
1897daaffb31Sdp
1898daaffb31Sdpif [[ -n $lflag ]]; then
1899daaffb31Sdp	#
1900daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
1901daaffb31Sdp	# then generate the file list by extracting file names from a
1902daaffb31Sdp	# putback -n.
1903daaffb31Sdp	#
1904daaffb31Sdp	shift $(($OPTIND - 1))
1905*cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1906daaffb31Sdp		flist_from_teamware "$*"
1907*cdf0c1d5Smjnelson	else
1908*cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
1909*cdf0c1d5Smjnelson		exit 1
1910*cdf0c1d5Smjnelson	fi
1911daaffb31Sdp	flist_done=1
1912daaffb31Sdp	shift $#
1913daaffb31Sdpelif [[ -n $wflag ]]; then
1914daaffb31Sdp	#
1915daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
1916daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
1917daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
1918daaffb31Sdp	# in building the index.html file.
1919daaffb31Sdp	#
1920daaffb31Sdp	shift $(($OPTIND - 1))
1921daaffb31Sdp	wxfile=$1
1922daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
1923daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
1924daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
1925daaffb31Sdp		fi
1926daaffb31Sdp	fi
1927daaffb31Sdp
1928daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
1929daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
1930daaffb31Sdp
1931*cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
1932*cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
1933*cdf0c1d5Smjnelson		usage
1934*cdf0c1d5Smjnelson	fi
1935*cdf0c1d5Smjnelson
1936daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
1937daaffb31Sdp	flist_from_wx $wxfile
1938daaffb31Sdp	flist_done=1
1939daaffb31Sdp	if [[ -n "$*" ]]; then
1940daaffb31Sdp		shift
1941daaffb31Sdp	fi
194214983201Sdpelif [[ $flist_mode == "stdin" ]]; then
194314983201Sdp	print -u2 " File list from: standard input"
194414983201Sdpelif [[ $flist_mode == "file" ]]; then
194514983201Sdp	print -u2 " File list from: $flist_file"
1946daaffb31Sdpfi
1947daaffb31Sdp
1948daaffb31Sdpif [[ $# -gt 0 ]]; then
194914983201Sdp	print -u2 "WARNING: unused arguments: $*"
1950daaffb31Sdpfi
1951daaffb31Sdp
1952daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
1953daaffb31Sdp	#
1954daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
1955daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
1956daaffb31Sdp	#
1957daaffb31Sdp	#      1) on the command line (only for the parent)
1958daaffb31Sdp	#      2) in the user environment
1959daaffb31Sdp	#      3) in the flist
1960daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
1961daaffb31Sdp	#
1962daaffb31Sdp
1963daaffb31Sdp	#
1964daaffb31Sdp	# Here is case (2): the user environment
1965daaffb31Sdp	#
1966daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
1967daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
1968daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
19697c478bd9Sstevel@tonic-gate		exit 1
19707c478bd9Sstevel@tonic-gate	fi
19717c478bd9Sstevel@tonic-gate
1972daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
1973daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
1974daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
1975daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
19767c478bd9Sstevel@tonic-gate		exit 1
19777c478bd9Sstevel@tonic-gate	fi
19787c478bd9Sstevel@tonic-gate
1979daaffb31Sdp	#
1980daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
1981daaffb31Sdp	# list, then see if we can get it by probing for wx.
1982daaffb31Sdp	#
198314983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
198414983201Sdp		if [[ ! -x $WX ]]; then
198514983201Sdp			print -u2 "WARNING: wx not found!"
1986daaffb31Sdp		fi
19877c478bd9Sstevel@tonic-gate
1988daaffb31Sdp		#
1989daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
1990daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
1991daaffb31Sdp		# hang asking us to initialize our wx information.
1992daaffb31Sdp		#
199314983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
1994daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
1995daaffb31Sdp			$WX list -w > $FLIST
1996daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
1997daaffb31Sdp			wxfile=/tmp/$$.wx_comments
1998daaffb31Sdp			print -u2 "done"
1999daaffb31Sdp			flist_done=1
2000daaffb31Sdp		fi
2001daaffb31Sdp	fi
2002daaffb31Sdp
2003daaffb31Sdp	#
2004daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2005daaffb31Sdp	# from the command line), eval it to extract environment variables from
2006daaffb31Sdp	# it: This is step (3).
2007daaffb31Sdp	#
2008daaffb31Sdp	env_from_flist
2009daaffb31Sdp
2010daaffb31Sdp	#
2011daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2012daaffb31Sdp	# it from teamware.
2013daaffb31Sdp	#
2014daaffb31Sdp	if [[ -z $flist_done ]]; then
2015daaffb31Sdp		flist_from_teamware
2016daaffb31Sdp		env_from_flist
2017daaffb31Sdp	fi
2018daaffb31Sdp
2019daaffb31Sdp	#
2020daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2021daaffb31Sdp	# from workspace.
2022daaffb31Sdp	#
2023*cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2024daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2025daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2026daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2027daaffb31Sdp		exit 1
2028daaffb31Sdp	fi
2029daaffb31Sdp
2030daaffb31Sdp	#
2031*cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2032*cdf0c1d5Smjnelson	# webrev title.
2033*cdf0c1d5Smjnelson	#
2034*cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2035*cdf0c1d5Smjnelson
2036*cdf0c1d5Smjnelson	#
2037daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2038daaffb31Sdp	#
2039daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2040daaffb31Sdp	CWS=$codemgr_ws
2041daaffb31Sdp	PWS=$codemgr_parent
2042*cdf0c1d5Smjnelson
2043*cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2044*cdf0c1d5Smjnelson
2045*cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2046*cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2047*cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2048*cdf0c1d5Smjnelson
2049*cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2050*cdf0c1d5Smjnelson
2051*cdf0c1d5Smjnelson	#
2052*cdf0c1d5Smjnelson	# Parent can either be specified with -p
2053*cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2054*cdf0c1d5Smjnelson	# or taken from hg's default path.
2055*cdf0c1d5Smjnelson	#
2056*cdf0c1d5Smjnelson
2057*cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2058*cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2059*cdf0c1d5Smjnelson	fi
2060*cdf0c1d5Smjnelson
2061*cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2062*cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2063*cdf0c1d5Smjnelson	fi
2064*cdf0c1d5Smjnelson
2065*cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2066*cdf0c1d5Smjnelson	CWS=$codemgr_ws
2067*cdf0c1d5Smjnelson	PWS=$codemgr_parent
2068*cdf0c1d5Smjnelson
2069*cdf0c1d5Smjnelson	#
2070*cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2071*cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2072*cdf0c1d5Smjnelson	#
2073*cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2074*cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2075*cdf0c1d5Smjnelson	else
2076*cdf0c1d5Smjnelson		real_parent=$PWS
2077*cdf0c1d5Smjnelson	fi
2078*cdf0c1d5Smjnelson
2079*cdf0c1d5Smjnelson	#
2080*cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2081*cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2082*cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2083*cdf0c1d5Smjnelson	# files mentioned in the flist.
2084*cdf0c1d5Smjnelson	#
2085*cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2086*cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2087*cdf0c1d5Smjnelson		flist_done=1
2088*cdf0c1d5Smjnelson	fi
2089*cdf0c1d5Smjnelson
2090*cdf0c1d5Smjnelson	#
2091*cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2092*cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2093*cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2094*cdf0c1d5Smjnelson	# in the user-specified flist.
2095*cdf0c1d5Smjnelson	#
2096*cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2097*cdf0c1d5Smjnelson		env_from_flist
2098*cdf0c1d5Smjnelson	fi
2099*cdf0c1d5Smjnelson
2100*cdf0c1d5Smjnelson	#
2101*cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2102*cdf0c1d5Smjnelson	#
2103*cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2104*cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2105*cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2106*cdf0c1d5Smjnelson		print " Done."
2107*cdf0c1d5Smjnelson	fi
2108*cdf0c1d5Smjnelson
2109*cdf0c1d5Smjnelson	#
2110*cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2111*cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2112*cdf0c1d5Smjnelson	# if we don't have one.
2113*cdf0c1d5Smjnelson	#
2114*cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2115*cdf0c1d5Smjnelson		eval `sed -e "s/#.*$//" $wxfile | grep HG_PARENT=`
2116*cdf0c1d5Smjnelson	fi
2117*cdf0c1d5Smjnelson
2118*cdf0c1d5Smjnelson	#
2119*cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2120*cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2121*cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2122*cdf0c1d5Smjnelson	#
2123*cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2124*cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2125*cdf0c1d5Smjnelson		    eval `sed -e "s/#.*$//" | grep HG_PARENT=`
2126*cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2127*cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2128*cdf0c1d5Smjnelson		exit 1
2129*cdf0c1d5Smjnelson	fi
2130*cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2131*cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2132*cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2133*cdf0c1d5Smjnelson	else
2134*cdf0c1d5Smjnelson		svn info | while read line; do
2135*cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2136*cdf0c1d5Smjnelson				url=${line#URL: }
2137*cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2138*cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2139*cdf0c1d5Smjnelson			fi
2140*cdf0c1d5Smjnelson		done
2141*cdf0c1d5Smjnelson
2142*cdf0c1d5Smjnelson		rel=${url#$repo}
2143*cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2144*cdf0c1d5Smjnelson	fi
2145*cdf0c1d5Smjnelson
2146*cdf0c1d5Smjnelson	#
2147*cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2148*cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2149*cdf0c1d5Smjnelson	#
2150*cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2151*cdf0c1d5Smjnelson
2152*cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2153*cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2154*cdf0c1d5Smjnelson	fi
2155*cdf0c1d5Smjnelsonelse
2156*cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2157*cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2158*cdf0c1d5Smjnelson    else
2159*cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2160*cdf0c1d5Smjnelson    fi
2161*cdf0c1d5Smjnelson
2162*cdf0c1d5Smjnelson    env_from_flist
2163*cdf0c1d5Smjnelson
2164*cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2165*cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2166*cdf0c1d5Smjnelson	exit 1
2167*cdf0c1d5Smjnelson    fi
2168*cdf0c1d5Smjnelson
2169*cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2170*cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2171*cdf0c1d5Smjnelson	exit 1
2172*cdf0c1d5Smjnelson    fi
2173*cdf0c1d5Smjnelson
2174*cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2175*cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2176daaffb31Sdpfi
2177daaffb31Sdp
2178daaffb31Sdp#
2179daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2180daaffb31Sdp# webrev-info file in the workspace directory.
2181daaffb31Sdp#
2182daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2183daaffb31Sdp	iflag=1
2184daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2185daaffb31Sdpfi
2186daaffb31Sdp
2187daaffb31Sdpif [[ -n $iflag ]]; then
2188daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2189daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2190daaffb31Sdp		    "not readable."
2191daaffb31Sdp		exit 1
2192daaffb31Sdp	else
2193daaffb31Sdp		#
2194daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2195daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2196daaffb31Sdp		#
2197daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2198daaffb31Sdp	fi
2199daaffb31Sdpfi
2200daaffb31Sdp
2201daaffb31Sdp#
2202daaffb31Sdp# Output directory.
2203daaffb31Sdp#
2204daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2205daaffb31Sdp
2206daaffb31Sdp#
2207daaffb31Sdp# Name of the webrev, derived from the workspace name; in the
2208daaffb31Sdp# future this could potentially be an option.
2209daaffb31Sdp#
2210daaffb31SdpWNAME=${CWS##*/}
2211daaffb31Sdp
2212e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
22137c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
22147c478bd9Sstevel@tonic-gatefi
2215daaffb31Sdp
2216daaffb31Sdpif [[ ! -d $WDIR ]]; then
2217daaffb31Sdp	mkdir -p $WDIR
2218daaffb31Sdp	[[ $? != 0 ]] && exit 1
22197c478bd9Sstevel@tonic-gatefi
22207c478bd9Sstevel@tonic-gate
2221daaffb31Sdp#
2222daaffb31Sdp# Summarize what we're going to do.
2223daaffb31Sdp#
2224*cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2225*cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2226*cdf0c1d5Smjnelsonelse
2227daaffb31Sdp	print "      Workspace: $CWS"
2228*cdf0c1d5Smjnelsonfi
2229daaffb31Sdpif [[ -n $parent_webrev ]]; then
2230daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2231daaffb31Sdpelse
2232*cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2233*cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2234*cdf0c1d5Smjnelson			| sed -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2235*cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2236*cdf0c1d5Smjnelson	else
2237daaffb31Sdp		print "Compare against: $PWS"
2238daaffb31Sdp	fi
2239*cdf0c1d5Smjnelsonfi
2240daaffb31Sdp
2241daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2242daaffb31Sdpprint "      Output to: $WDIR"
2243daaffb31Sdp
2244daaffb31Sdp#
22457c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2246daaffb31Sdp#
2247daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
22487c478bd9Sstevel@tonic-gate
2249daaffb31Sdp#
2250daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2251daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2252daaffb31Sdp#
2253daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2254daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2255daaffb31Sdp[[ -n "$Oflag" ]] && \
2256daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
22577c478bd9Sstevel@tonic-gate
2258daaffb31Sdp#
2259daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2260daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2261daaffb31Sdp#
2262daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2263daaffb31Sdp#    SACURL.  See sac2url().
2264daaffb31Sdp#
2265daaffb31SdpSACURL='http://sac.eng.sun.com'
2266daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2267e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2268daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
22697c478bd9Sstevel@tonic-gate
2270daaffb31Sdprm -f $WDIR/$WNAME.patch
2271daaffb31Sdprm -f $WDIR/$WNAME.ps
2272daaffb31Sdprm -f $WDIR/$WNAME.pdf
22737c478bd9Sstevel@tonic-gate
2274daaffb31Sdptouch $WDIR/$WNAME.patch
22757c478bd9Sstevel@tonic-gate
2276daaffb31Sdpprint "   Output Files:"
2277daaffb31Sdp
2278daaffb31Sdp#
2279daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2280daaffb31Sdp#
2281daaffb31Sdpsed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2282daaffb31SdpFLIST=/tmp/$$.flist.clean
2283daaffb31Sdp
2284daaffb31Sdp#
2285*cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2286*cdf0c1d5Smjnelson#
2287*cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2288*cdf0c1d5Smjnelson	#
2289*cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2290*cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2291*cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2292*cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2293*cdf0c1d5Smjnelson	#    keep only the old name.
2294*cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2295*cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2296*cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2297*cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2298*cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2299*cdf0c1d5Smjnelson	#
2300*cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2301*cdf0c1d5Smjnelson	sed '
2302*cdf0c1d5Smjnelson		s#^[^ ]* ##
2303*cdf0c1d5Smjnelson		s#/#\\\/#g
2304*cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2305*cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2306*cdf0c1d5Smjnelson
2307*cdf0c1d5Smjnelson	#
2308*cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2309*cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2310*cdf0c1d5Smjnelson	#
2311*cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2312*cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2313*cdf0c1d5Smjnelson	    sed -n -f $SEDFILE > $HG_PARENT_MANIFEST
2314*cdf0c1d5Smjnelsonfi
2315*cdf0c1d5Smjnelson
2316*cdf0c1d5Smjnelson#
2317daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2318daaffb31Sdp#
2319daaffb31Sdpcat $FLIST | while read LINE
23207c478bd9Sstevel@tonic-gatedo
23217c478bd9Sstevel@tonic-gate	set - $LINE
23227c478bd9Sstevel@tonic-gate	P=$1
23237c478bd9Sstevel@tonic-gate
2324daaffb31Sdp	#
2325daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2326daaffb31Sdp	# file that has been modified or created in the child.  A file
2327daaffb31Sdp	# that is renamed in the child workspace has two names on the
2328daaffb31Sdp	# line: new name followed by the old name.
2329daaffb31Sdp	#
2330daaffb31Sdp	oldname=""
2331daaffb31Sdp	oldpath=""
2332daaffb31Sdp	rename=
2333daaffb31Sdp	if [[ $# -eq 2 ]]; then
23347c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2335daaffb31Sdp		oldname=" (was $PP)"
2336daaffb31Sdp		oldpath="$PP"
2337daaffb31Sdp		rename=1
23387c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2339daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
23407c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
23417c478bd9Sstevel@tonic-gate		fi
23427c478bd9Sstevel@tonic-gate
23437c478bd9Sstevel@tonic-gate		PF=${PP##*/}
23447c478bd9Sstevel@tonic-gate
23457c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2346daaffb31Sdp	        if [[ $DIR == $P ]]; then
23477c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
23487c478bd9Sstevel@tonic-gate		fi
23497c478bd9Sstevel@tonic-gate
23507c478bd9Sstevel@tonic-gate		F=${P##*/}
2351daaffb31Sdp
23527c478bd9Sstevel@tonic-gate        else
23537c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2354daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
23557c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
23567c478bd9Sstevel@tonic-gate		fi
23577c478bd9Sstevel@tonic-gate
23587c478bd9Sstevel@tonic-gate		F=${P##*/}
23597c478bd9Sstevel@tonic-gate
23607c478bd9Sstevel@tonic-gate		PP=$P
23617c478bd9Sstevel@tonic-gate		PDIR=$DIR
23627c478bd9Sstevel@tonic-gate		PF=$F
23637c478bd9Sstevel@tonic-gate	fi
23647c478bd9Sstevel@tonic-gate
2365daaffb31Sdp	COMM=`getcomments html $P $PP`
23667c478bd9Sstevel@tonic-gate
2367daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
23707c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
23717c478bd9Sstevel@tonic-gate
2372daaffb31Sdp	#
2373daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2374daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2375e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2376daaffb31Sdp	#
2377e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2378daaffb31Sdp		pclosed=${P##usr/closed/}
2379e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2380e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2381daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2382daaffb31Sdp			    "mode review"
2383daaffb31Sdp			continue
2384daaffb31Sdp		fi
2385daaffb31Sdp	fi
2386daaffb31Sdp
2387daaffb31Sdp	#
2388*cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2389daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2390daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2391daaffb31Sdp	#
2392daaffb31Sdp
2393*cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
23947c478bd9Sstevel@tonic-gate	    continue
23957c478bd9Sstevel@tonic-gate
2396*cdf0c1d5Smjnelson	#
2397*cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2398*cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2399*cdf0c1d5Smjnelson	# consistent environment.
2400*cdf0c1d5Smjnelson	#
2401*cdf0c1d5Smjnelson	OWD=$PWD
2402daaffb31Sdp	cd $WDIR/raw_files
2403daaffb31Sdp	ofile=old/$PDIR/$PF
2404daaffb31Sdp	nfile=new/$DIR/$F
24057c478bd9Sstevel@tonic-gate
2406daaffb31Sdp	mv_but_nodiff=
2407daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2408daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2409daaffb31Sdp		mv_but_nodiff=1
2410daaffb31Sdp	fi
2411daaffb31Sdp
2412daaffb31Sdp	#
2413daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2414daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2415daaffb31Sdp	#
2416daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2417daaffb31Sdp	#	  diff and an 'add' diff
2418daaffb31Sdp	#	- new files and deleted files must be handled specially
2419daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2420daaffb31Sdp	#	  (and hence renames) as of this writing.
2421daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2422daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2423daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2424daaffb31Sdp	#         transformations:
2425daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2426daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2427daaffb31Sdp	#
2428daaffb31Sdp	cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2429daaffb31Sdp	cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2430daaffb31Sdp
2431daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2432daaffb31Sdp	if [[ -z $rename ]]; then
2433e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2434daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2435daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2436e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2437daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2438daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2439daaffb31Sdp		else
2440daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2441daaffb31Sdp		fi
2442daaffb31Sdp	else
2443daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2444daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2445daaffb31Sdp
2446daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2447daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2448daaffb31Sdp
2449daaffb31Sdp	fi
2450daaffb31Sdp
2451daaffb31Sdp	#
2452daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2453daaffb31Sdp	# whole wad.
2454daaffb31Sdp	#
2455daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2456daaffb31Sdp
2457daaffb31Sdp	print " patch\c"
2458daaffb31Sdp
2459daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2460daaffb31Sdp
2461daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2462daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2463daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
24647c478bd9Sstevel@tonic-gate		print " cdiffs\c"
24657c478bd9Sstevel@tonic-gate
2466daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2467daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2468daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2469daaffb31Sdp
24707c478bd9Sstevel@tonic-gate		print " udiffs\c"
24717c478bd9Sstevel@tonic-gate
24727c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2473daaffb31Sdp			$WDIFF -c "$COMM" \
2474daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2475daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2476daaffb31Sdp			if [[ $? -eq 0 ]]; then
24777c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2478daaffb31Sdp			else
2479daaffb31Sdp				print " wdiffs[fail]\c"
2480daaffb31Sdp			fi
24817c478bd9Sstevel@tonic-gate		fi
24827c478bd9Sstevel@tonic-gate
2483daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2484daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
24857c478bd9Sstevel@tonic-gate		print " sdiffs\c"
24867c478bd9Sstevel@tonic-gate
24877c478bd9Sstevel@tonic-gate		print " frames\c"
24887c478bd9Sstevel@tonic-gate
24897c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
24907c478bd9Sstevel@tonic-gate
2491daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2492daaffb31Sdp
2493daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2494daaffb31Sdp		# renamed file: may also have differences
2495daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2496daaffb31Sdp	elif [[ -f $nfile ]]; then
24977c478bd9Sstevel@tonic-gate		# new file: count added lines
2498daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2499daaffb31Sdp	elif [[ -f $ofile ]]; then
25007c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2501daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
25027c478bd9Sstevel@tonic-gate	fi
25037c478bd9Sstevel@tonic-gate
2504daaffb31Sdp	#
2505daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
2506daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
2507daaffb31Sdp	# tree-killing to print out the contents of deleted files).
2508daaffb31Sdp	#
2509daaffb31Sdp	if [[ -f $nfile ]]; then
2510daaffb31Sdp		ocr=$ofile
2511daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
2512daaffb31Sdp
2513daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
2514daaffb31Sdp			textcomm=`getcomments text $P $PP`
251514983201Sdp			if [[ -x $CODEREVIEW ]]; then
251614983201Sdp				$CODEREVIEW -y "$textcomm" \
251714983201Sdp				    -e $ocr $nfile \
251814983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
251914983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
2520daaffb31Sdp				if [[ $? -eq 0 ]]; then
2521daaffb31Sdp					print " ps\c"
2522daaffb31Sdp				else
2523daaffb31Sdp					print " ps[fail]\c"
2524daaffb31Sdp				fi
2525daaffb31Sdp			fi
2526daaffb31Sdp		fi
252714983201Sdp	fi
2528daaffb31Sdp
2529*cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
2530*cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
25317c478bd9Sstevel@tonic-gate		print " old\c"
25327c478bd9Sstevel@tonic-gate	fi
25337c478bd9Sstevel@tonic-gate
2534daaffb31Sdp	if [[ -f $nfile ]]; then
2535daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
25367c478bd9Sstevel@tonic-gate		print " new\c"
25377c478bd9Sstevel@tonic-gate	fi
25387c478bd9Sstevel@tonic-gate
2539*cdf0c1d5Smjnelson	cd $OWD
2540*cdf0c1d5Smjnelson
2541daaffb31Sdp	print
25427c478bd9Sstevel@tonic-gatedone
25437c478bd9Sstevel@tonic-gate
2544daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
25457c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
2546daaffb31Sdp
254714983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
254814983201Sdp	print " Generating PDF: Skipped: no output available"
254914983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
255014983201Sdp	print " Generating PDF: \c"
255114983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
2552daaffb31Sdp	print "Done."
255314983201Sdpelse
255414983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
255514983201Sdpfi
25567c478bd9Sstevel@tonic-gate
2557e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
2558e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
2559e0e0293aSjmcp
2560e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
2561e0e0293aSjmcp	/usr/bin/find $WDIR -type d -name closed -exec /bin/rm -rf {} \;
2562e0e0293aSjmcpfi
2563e0e0293aSjmcp
25647c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
25657c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
25667c478bd9Sstevel@tonic-gate
25677c478bd9Sstevel@tonic-gatecd $CWS
25687c478bd9Sstevel@tonic-gate
25697c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
2570daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
25717c478bd9Sstevel@tonic-gate
2572daaffb31Sdpprint "     index.html: \c"
25737c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
25747c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
25757c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
25767c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
25777c478bd9Sstevel@tonic-gate
2578daaffb31Sdpprint "$HTML<head>$STDHEAD"
2579daaffb31Sdpprint "<title>$WNAME</title>"
2580daaffb31Sdpprint "</head>"
2581daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
2582daaffb31Sdpprint "<div class=\"summary\">"
2583daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
25847c478bd9Sstevel@tonic-gate
2585daaffb31Sdpprint "<table>"
25867c478bd9Sstevel@tonic-gate
2587daaffb31Sdp#
2588*cdf0c1d5Smjnelson# Get the preparer's name:
2589daaffb31Sdp#
2590*cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
2591*cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
2592*cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
2593*cdf0c1d5Smjnelson#
2594*cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
2595*cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
2596*cdf0c1d5Smjnelson#
2597*cdf0c1d5Smjnelsonpreparer=
2598*cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
2599*cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
2600*cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
2601*cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
2602*cdf0c1d5Smjnelson	fi
2603*cdf0c1d5Smjnelsonfi
2604*cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
2605*cdf0c1d5Smjnelson	preparer=$(
2606*cdf0c1d5Smjnelson	    $PERL -e '
2607*cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
2608*cdf0c1d5Smjnelson	        if ($login) {
2609*cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
2610*cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
2611*cdf0c1d5Smjnelson	        } else {
2612*cdf0c1d5Smjnelson	            printf "(unknown)\n";
2613*cdf0c1d5Smjnelson	        }
2614*cdf0c1d5Smjnelson	')
2615daaffb31Sdpfi
2616daaffb31Sdp
2617*cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
2618*cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
2619*cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2620*cdf0c1d5Smjnelson	print "(at $CWS_REV)"
2621*cdf0c1d5Smjnelsonfi
2622*cdf0c1d5Smjnelsonprint "</td></tr>"
2623daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
2624daaffb31Sdpif [[ -n $parent_webrev ]]; then
2625daaffb31Sdp	print "webrev at $parent_webrev"
2626daaffb31Sdpelse
2627daaffb31Sdp	print "$PWS"
2628*cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
2629*cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
2630*cdf0c1d5Smjnelson	fi
2631daaffb31Sdpfi
2632daaffb31Sdpprint "</td></tr>"
2633daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
2634daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
2635daaffb31Sdpprint "</td></tr>"
2636daaffb31Sdp
2637daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
2638daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
2639daaffb31Sdp	print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
2640daaffb31Sdpfi
2641daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
2642daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
2643daaffb31Sdp	print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
2644daaffb31Sdpfi
2645daaffb31Sdp
2646daaffb31Sdpif [[ -n "$iflag" ]]; then
2647daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
2648daaffb31Sdp	cat /tmp/$$.include
2649daaffb31Sdp	print "</div></td></tr>"
2650daaffb31Sdpfi
2651daaffb31Sdpprint "</table>"
2652daaffb31Sdpprint "</div>"
2653daaffb31Sdp
2654daaffb31Sdp#
2655daaffb31Sdp# Second pass through the files: generate the rest of the index file
2656daaffb31Sdp#
2657daaffb31Sdpcat $FLIST | while read LINE
26587c478bd9Sstevel@tonic-gatedo
26597c478bd9Sstevel@tonic-gate	set - $LINE
26607c478bd9Sstevel@tonic-gate	P=$1
26617c478bd9Sstevel@tonic-gate
2662daaffb31Sdp	if [[ $# == 2 ]]; then
26637c478bd9Sstevel@tonic-gate		PP=$2
2664*cdf0c1d5Smjnelson		oldname="$PP"
26657c478bd9Sstevel@tonic-gate	else
26667c478bd9Sstevel@tonic-gate		PP=$P
2667daaffb31Sdp		oldname=""
2668daaffb31Sdp	fi
2669daaffb31Sdp
2670*cdf0c1d5Smjnelson	mv_but_nodiff=
2671*cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
2672*cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
2673*cdf0c1d5Smjnelson		mv_but_nodiff=1
2674*cdf0c1d5Smjnelson	fi
2675*cdf0c1d5Smjnelson
2676daaffb31Sdp	DIR=${P%/*}
2677daaffb31Sdp	if [[ $DIR == $P ]]; then
2678daaffb31Sdp		DIR="."   # File at root of workspace
26797c478bd9Sstevel@tonic-gate	fi
26807c478bd9Sstevel@tonic-gate
26817c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
26827c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
26837c478bd9Sstevel@tonic-gate	# appear twice in the file list
26847c478bd9Sstevel@tonic-gate
26857c478bd9Sstevel@tonic-gate	F=$WDIR/$P
26867c478bd9Sstevel@tonic-gate
2687daaffb31Sdp	print "<p>"
26887c478bd9Sstevel@tonic-gate
26897c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
26907c478bd9Sstevel@tonic-gate
2691daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
2692daaffb31Sdp		print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
2693daaffb31Sdp		print "<a href=\"$P.udiff.html\">Udiffs</a>"
26947c478bd9Sstevel@tonic-gate
2695daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
2696daaffb31Sdp			print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
26977c478bd9Sstevel@tonic-gate		fi
26987c478bd9Sstevel@tonic-gate
2699daaffb31Sdp		print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
27007c478bd9Sstevel@tonic-gate
27017c478bd9Sstevel@tonic-gate		print "<a href=\"$P.frames.html\">Frames</a>"
27027c478bd9Sstevel@tonic-gate	else
2703daaffb31Sdp		print " ------ ------ ------"
27047c478bd9Sstevel@tonic-gate
2705daaffb31Sdp		if [[ -x $WDIFF ]]; then
27067c478bd9Sstevel@tonic-gate			print " ------"
27077c478bd9Sstevel@tonic-gate		fi
2708daaffb31Sdp
2709daaffb31Sdp		print " ------"
27107c478bd9Sstevel@tonic-gate	fi
27117c478bd9Sstevel@tonic-gate
27127c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
27137c478bd9Sstevel@tonic-gate
2714daaffb31Sdp	if [[ -f $F-.html ]]; then
2715daaffb31Sdp		print "<a href=\"$P-.html\">Old</a>"
27167c478bd9Sstevel@tonic-gate	else
2717daaffb31Sdp		print " ---"
27187c478bd9Sstevel@tonic-gate	fi
27197c478bd9Sstevel@tonic-gate
27207c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
27217c478bd9Sstevel@tonic-gate
2722daaffb31Sdp	if [[ -f $F.html ]]; then
2723daaffb31Sdp		print "<a href=\"$P.html\">New</a>"
27247c478bd9Sstevel@tonic-gate	else
2725daaffb31Sdp		print " ---"
27267c478bd9Sstevel@tonic-gate	fi
27277c478bd9Sstevel@tonic-gate
2728daaffb31Sdp	if [[ -f $F.patch ]]; then
2729daaffb31Sdp		print "<a href=\"$P.patch\">Patch</a>"
2730daaffb31Sdp	else
2731daaffb31Sdp		print " -----"
2732daaffb31Sdp	fi
2733daaffb31Sdp
2734daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
2735daaffb31Sdp		print "<a href=\"raw_files/new/$P\">Raw</a>"
2736daaffb31Sdp	else
2737daaffb31Sdp		print " ---"
2738daaffb31Sdp	fi
2739daaffb31Sdp
2740*cdf0c1d5Smjnelson	print "<b>$P</b>"
2741*cdf0c1d5Smjnelson
2742*cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
2743*cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
2744*cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
2745*cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
2746*cdf0c1d5Smjnelson		else
2747*cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
2748*cdf0c1d5Smjnelson		fi
2749*cdf0c1d5Smjnelson	fi
2750*cdf0c1d5Smjnelson
2751*cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
2752*cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
2753*cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
2754*cdf0c1d5Smjnelson	fi
2755daaffb31Sdp
2756daaffb31Sdp	#
2757e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
2758daaffb31Sdp	#
2759daaffb31Sdp	if [ ! -z "$Oflag" ]; then
2760e0e0293aSjmcp		if [[ $P == usr/closed/* || \
2761e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
2762daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
2763daaffb31Sdp			    "this review</i>"
2764daaffb31Sdp		fi
2765daaffb31Sdp	fi
2766daaffb31Sdp
2767daaffb31Sdp	print "</p>"
27687c478bd9Sstevel@tonic-gate	# Insert delta comments
27697c478bd9Sstevel@tonic-gate
2770daaffb31Sdp	print "<blockquote><pre>"
2771daaffb31Sdp	getcomments html $P $PP
2772daaffb31Sdp	print "</pre>"
27737c478bd9Sstevel@tonic-gate
27747c478bd9Sstevel@tonic-gate	# Add additional comments comment
27757c478bd9Sstevel@tonic-gate
2776daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
27777c478bd9Sstevel@tonic-gate
27787c478bd9Sstevel@tonic-gate	# Add count of changes.
27797c478bd9Sstevel@tonic-gate
2780daaffb31Sdp	if [[ -f $F.count ]]; then
27817c478bd9Sstevel@tonic-gate	    cat $F.count
27827c478bd9Sstevel@tonic-gate	    rm $F.count
27837c478bd9Sstevel@tonic-gate	fi
2784*cdf0c1d5Smjnelson
2785*cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
2786*cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
2787*cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
2788*cdf0c1d5Smjnelson
2789*cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
2790*cdf0c1d5Smjnelson		# 1) New executable files
2791*cdf0c1d5Smjnelson		# 2) Permission changes of any kind
2792*cdf0c1d5Smjnelson		# 3) Existing executable files
2793*cdf0c1d5Smjnelson
2794*cdf0c1d5Smjnelson		old_mode=
2795*cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
2796*cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
2797*cdf0c1d5Smjnelson		fi
2798*cdf0c1d5Smjnelson
2799*cdf0c1d5Smjnelson		new_mode=
2800*cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
2801*cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
2802*cdf0c1d5Smjnelson		fi
2803*cdf0c1d5Smjnelson
2804*cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
2805*cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2806*cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
2807*cdf0c1d5Smjnelson			print "</span>"
2808*cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
2809*cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
2810*cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2811*cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
2812*cdf0c1d5Smjnelson			print "</span>"
2813*cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
2814*cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
2815*cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
2816*cdf0c1d5Smjnelson			print "</span>"
2817*cdf0c1d5Smjnelson		fi
2818*cdf0c1d5Smjnelson	fi
2819*cdf0c1d5Smjnelson
2820daaffb31Sdp	print "</blockquote>"
28217c478bd9Sstevel@tonic-gatedone
28227c478bd9Sstevel@tonic-gate
2823daaffb31Sdpprint
2824daaffb31Sdpprint
2825cac38512Smjnelsonprint "<hr></hr>"
2826daaffb31Sdpprint "<p style=\"font-size: small\">"
2827daaffb31Sdpprint "This code review page was prepared using <b>$0</b>"
2828daaffb31Sdpprint "(vers $WEBREV_UPDATED)."
2829daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
2830daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
2831e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
2832daaffb31Sdpprint "</body>"
2833daaffb31Sdpprint "</html>"
28347c478bd9Sstevel@tonic-gate
28357c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
28367c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
28377c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
28387c478bd9Sstevel@tonic-gate
2839daaffb31Sdpprint "Done."
2840