xref: /titanic_54/usr/src/tools/scripts/webrev.sh (revision 02d26c39c38c50cee317dd3a02c320bbf1e5a099)
17c478bd9Sstevel@tonic-gate#!/usr/bin/ksh -p
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6daaffb31Sdp# Common Development and Distribution License (the "License").
7daaffb31Sdp# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
229a70fc3bSMark J. Nelson
237c478bd9Sstevel@tonic-gate#
24cac38512Smjnelson# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate# Use is subject to license terms.
267c478bd9Sstevel@tonic-gate#
27cdf0c1d5Smjnelson
28cdf0c1d5Smjnelson#
29daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
30daaffb31Sdp# suitable for doing a code review of source changes via a web page.
31daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
32daaffb31Sdp# type 'webrev -h'.
337c478bd9Sstevel@tonic-gate#
34daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
35daaffb31Sdp# man page.
367c478bd9Sstevel@tonic-gate#
37daaffb31Sdp
387c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
397c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
407c478bd9Sstevel@tonic-gateNEW_COLOR=blue
417c478bd9Sstevel@tonic-gate
42daaffb31SdpHTML='<?xml version="1.0"?>
43daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
44daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
45daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
46daaffb31Sdp
47daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
48daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
49daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
50daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
51daaffb31Sdp
52cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
53cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
54cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
55daaffb31Sdp<!--
56daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
57daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
58daaffb31Sdp   mechanism available in some browsers.
59daaffb31Sdp
60daaffb31Sdp   For example, to have all "removed" information be red instead of
61daaffb31Sdp   brown, set a rule in your userContent.css file like:
62daaffb31Sdp
63daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
64daaffb31Sdp-->
65daaffb31Sdp<style type="text/css" media="screen">
66daaffb31Sdpbody {
67daaffb31Sdp    background-color: #eeeeee;
68daaffb31Sdp}
69daaffb31Sdphr {
70daaffb31Sdp    border: none 0;
71daaffb31Sdp    border-top: 1px solid #aaa;
72daaffb31Sdp    height: 1px;
73daaffb31Sdp}
74daaffb31Sdpdiv.summary {
75daaffb31Sdp    font-size: .8em;
76daaffb31Sdp    border-bottom: 1px solid #aaa;
77daaffb31Sdp    padding-left: 1em;
78daaffb31Sdp    padding-right: 1em;
79daaffb31Sdp}
80daaffb31Sdpdiv.summary h2 {
81daaffb31Sdp    margin-bottom: 0.3em;
82daaffb31Sdp}
83daaffb31Sdpdiv.summary table th {
84daaffb31Sdp    text-align: right;
85daaffb31Sdp    vertical-align: top;
86daaffb31Sdp    white-space: nowrap;
87daaffb31Sdp}
88daaffb31Sdpspan.lineschanged {
89daaffb31Sdp    font-size: 0.7em;
90daaffb31Sdp}
91daaffb31Sdpspan.oldmarker {
92daaffb31Sdp    color: red;
93daaffb31Sdp    font-size: large;
94daaffb31Sdp    font-weight: bold;
95daaffb31Sdp}
96daaffb31Sdpspan.newmarker {
97daaffb31Sdp    color: green;
98daaffb31Sdp    font-size: large;
99daaffb31Sdp    font-weight: bold;
100daaffb31Sdp}
101daaffb31Sdpspan.removed {
102daaffb31Sdp    color: brown;
103daaffb31Sdp}
104daaffb31Sdpspan.changed {
105daaffb31Sdp    color: blue;
106daaffb31Sdp}
107daaffb31Sdpspan.new {
108daaffb31Sdp    color: blue;
109daaffb31Sdp    font-weight: bold;
110daaffb31Sdp}
111cdf0c1d5Smjnelsonspan.chmod {
112cdf0c1d5Smjnelson    font-size: 0.7em;
113cdf0c1d5Smjnelson    color: #db7800;
114cdf0c1d5Smjnelson}
115daaffb31Sdpa.print { font-size: x-small; }
116daaffb31Sdpa:hover { background-color: #ffcc99; }
117daaffb31Sdp</style>
118daaffb31Sdp
119daaffb31Sdp<style type="text/css" media="print">
120daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
121daaffb31Sdpspan.removed { color: #444; font-style: italic }
122daaffb31Sdpspan.changed { font-weight: bold; }
123daaffb31Sdpspan.new { font-weight: bold; }
124daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
125daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
126daaffb31Sdpa.print {display: none}
127daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
128daaffb31Sdp</style>
129daaffb31Sdp'
130daaffb31Sdp
131daaffb31Sdp#
132daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
133daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
134daaffb31Sdp#
135daaffb31SdpUDIFFCSS='
136daaffb31Sdp<style type="text/css" media="screen">
137daaffb31Sdpspan.new {
138daaffb31Sdp    color: blue;
139daaffb31Sdp    font-weight: normal;
140daaffb31Sdp}
141daaffb31Sdp</style>
142daaffb31Sdp'
143daaffb31Sdp
144*02d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
145*02d26c39SVladimir Kotalrsync_upload()
146*02d26c39SVladimir Kotal{
147*02d26c39SVladimir Kotal	if (( $# != 1 )); then
148*02d26c39SVladimir Kotal		return 1
149*02d26c39SVladimir Kotal	fi
150*02d26c39SVladimir Kotal
151*02d26c39SVladimir Kotal	typeset dst=$1
152*02d26c39SVladimir Kotal
153*02d26c39SVladimir Kotal	# if destination specification is not in the form of host:remote_dir
154*02d26c39SVladimir Kotal	# then assume it is just remote hostname and append a colon and
155*02d26c39SVladimir Kotal	# destination directory formed from local webrev directory name
156*02d26c39SVladimir Kotal	if [[ -z ${dst##*:} ]]; then
157*02d26c39SVladimir Kotal		if [[ "${dst}" == *: ]]; then
158*02d26c39SVladimir Kotal			dst=${dst}${WNAME}
159*02d26c39SVladimir Kotal		else
160*02d26c39SVladimir Kotal			dst=${dst}:${WNAME}
161*02d26c39SVladimir Kotal		fi
162*02d26c39SVladimir Kotal	fi
163*02d26c39SVladimir Kotal
164*02d26c39SVladimir Kotal	print " Syncing webrev: \c"
165*02d26c39SVladimir Kotal	# end source directory with a slash in order to copy just
166*02d26c39SVladimir Kotal	# directory contents, not the whole directory
167*02d26c39SVladimir Kotal	$RSYNC -r -q $WDIR/ $dst
168*02d26c39SVladimir Kotal	if (( $? != 0 )); then
169*02d26c39SVladimir Kotal		print "failed to sync webrev directory " \
170*02d26c39SVladimir Kotal		    "'$WDIR' to '$dst'"
171*02d26c39SVladimir Kotal		return 1
172*02d26c39SVladimir Kotal	fi
173*02d26c39SVladimir Kotal
174*02d26c39SVladimir Kotal	print "Done."
175*02d26c39SVladimir Kotal	return 0
176*02d26c39SVladimir Kotal}
177*02d26c39SVladimir Kotal
178*02d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
179*02d26c39SVladimir Kotalssh_upload()
180*02d26c39SVladimir Kotal{
181*02d26c39SVladimir Kotal	if (( $# != 1 )); then
182*02d26c39SVladimir Kotal		return 1
183*02d26c39SVladimir Kotal	fi
184*02d26c39SVladimir Kotal
185*02d26c39SVladimir Kotal	typeset dst=$1
186*02d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
187*02d26c39SVladimir Kotal	typeset -r dir_spec=${dst##*:}
188*02d26c39SVladimir Kotal
189*02d26c39SVladimir Kotal	# if destination specification is not in the form of host:remote_dir
190*02d26c39SVladimir Kotal	# then assume it is just remote hostname and append a colon
191*02d26c39SVladimir Kotal	if [[ "${dst}" != *:* ]]; then
192*02d26c39SVladimir Kotal		dst=${dst}:
193*02d26c39SVladimir Kotal	fi
194*02d26c39SVladimir Kotal
195*02d26c39SVladimir Kotal	if [[ -z $tflag || -z $dir_spec ]]; then
196*02d26c39SVladimir Kotal		dir_rm=$WNAME
197*02d26c39SVladimir Kotal	else
198*02d26c39SVladimir Kotal		if [[ "${dir_spec}" == */* ]]; then
199*02d26c39SVladimir Kotal			dir_rm=${dir_spec%%/*}
200*02d26c39SVladimir Kotal		else
201*02d26c39SVladimir Kotal			dir_rm=${dir_spec##*/}
202*02d26c39SVladimir Kotal		fi
203*02d26c39SVladimir Kotal	fi
204*02d26c39SVladimir Kotal
205*02d26c39SVladimir Kotal	if [[ "${dir_spec}" != /* ]]; then
206*02d26c39SVladimir Kotal		print "Removing old remote webrev: \c"
207*02d26c39SVladimir Kotal		if [[ -z "$dir_rm" ]]; then
208*02d26c39SVladimir Kotal			echo "empty directory for removal"
209*02d26c39SVladimir Kotal			return 1
210*02d26c39SVladimir Kotal		fi
211*02d26c39SVladimir Kotal		typeset -r batch_file_rm=$( $MKTEMP /tmp/$webrev_remove.XXX )
212*02d26c39SVladimir Kotal		echo "rename $dir_rm .trash/removed.$$" > $batch_file_rm
213*02d26c39SVladimir Kotal		# we do not care about return value because this might be
214*02d26c39SVladimir Kotal		# the first time this directory is uploaded
215*02d26c39SVladimir Kotal		$SFTP -b $batch_file_rm $host_spec 2>/dev/null 1>&2
216*02d26c39SVladimir Kotal		rm -f $batch_file_rm
217*02d26c39SVladimir Kotal		print "Done."
218*02d26c39SVladimir Kotal	fi
219*02d26c39SVladimir Kotal
220*02d26c39SVladimir Kotal	# if the supplied path is absolute we assume all directories are
221*02d26c39SVladimir Kotal	# created, otherwise try to create all directories in the path
222*02d26c39SVladimir Kotal	# except the last one which will be created by scp
223*02d26c39SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
224*02d26c39SVladimir Kotal		print "Creating directories: \c"
225*02d26c39SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
226*02d26c39SVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP /tmp/$webrev_mkdir.XXX )
227*02d26c39SVladimir Kotal                OLDIFS=$IFS
228*02d26c39SVladimir Kotal                IFS=/
229*02d26c39SVladimir Kotal                mk=
230*02d26c39SVladimir Kotal                for dir in $dirs_mk; do
231*02d26c39SVladimir Kotal                        if [[ -z $mk ]]; then
232*02d26c39SVladimir Kotal                                mk=$dir
233*02d26c39SVladimir Kotal                        else
234*02d26c39SVladimir Kotal                                mk=$mk/$dir
235*02d26c39SVladimir Kotal                        fi
236*02d26c39SVladimir Kotal                        echo "mkdir $mk" >> $batch_file_mkdir
237*02d26c39SVladimir Kotal                done
238*02d26c39SVladimir Kotal                IFS=$OLDIFS
239*02d26c39SVladimir Kotal		$SFTP -b $batch_file_mkdir $host_spec 2>/dev/null 1>&2
240*02d26c39SVladimir Kotal		if (( $? != 0 )); then
241*02d26c39SVladimir Kotal			echo "Failed to create remote directories"
242*02d26c39SVladimir Kotal			rm -f $batch_file_mkdir
243*02d26c39SVladimir Kotal			return 1
244*02d26c39SVladimir Kotal		fi
245*02d26c39SVladimir Kotal		rm -f $batch_file_mkdir
246*02d26c39SVladimir Kotal		print "Done."
247*02d26c39SVladimir Kotal	fi
248*02d26c39SVladimir Kotal
249*02d26c39SVladimir Kotal	print "Uploading webrev: \c"
250*02d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
251*02d26c39SVladimir Kotal		$WDIR $dst
252*02d26c39SVladimir Kotal	if (( $? != 0 )); then
253*02d26c39SVladimir Kotal		print "failed to upload webrev directory" \
254*02d26c39SVladimir Kotal		    "'$WDIR' to '$dst'"
255*02d26c39SVladimir Kotal		return 1
256*02d26c39SVladimir Kotal	fi
257*02d26c39SVladimir Kotal
258*02d26c39SVladimir Kotal	print "Done."
259*02d26c39SVladimir Kotal	return 0
260*02d26c39SVladimir Kotal}
261*02d26c39SVladimir Kotal
262*02d26c39SVladimir Kotal#
263*02d26c39SVladimir Kotal# Upload webrev to remote site
264*02d26c39SVladimir Kotal#
265*02d26c39SVladimir Kotalupload_webrev()
266*02d26c39SVladimir Kotal{
267*02d26c39SVladimir Kotal	# default host
268*02d26c39SVladimir Kotal	host_spec="cr.opensolaris.org"
269*02d26c39SVladimir Kotal	typeset -r rsync_prefix="rsync://"
270*02d26c39SVladimir Kotal	typeset -r ssh_prefix="ssh://"
271*02d26c39SVladimir Kotal
272*02d26c39SVladimir Kotal	# if remote target is not specified, build the target from scratch
273*02d26c39SVladimir Kotal	# using the default values
274*02d26c39SVladimir Kotal	if [[ -z $tflag ]]; then
275*02d26c39SVladimir Kotal		dst_rsync="$host_spec:$WNAME"
276*02d26c39SVladimir Kotal		dst_ssh="$host_spec:$WNAME"
277*02d26c39SVladimir Kotal	fi
278*02d26c39SVladimir Kotal
279*02d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
280*02d26c39SVladimir Kotal		echo "webrev directory '$WDIR' does not exist"
281*02d26c39SVladimir Kotal		return 1
282*02d26c39SVladimir Kotal	fi
283*02d26c39SVladimir Kotal
284*02d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
285*02d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
286*02d26c39SVladimir Kotal	# target he probably knows what he is doing.
287*02d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
288*02d26c39SVladimir Kotal		/usr/bin/find $WDIR -type d -name closed \
289*02d26c39SVladimir Kotal			| $GREP closed >/dev/null
290*02d26c39SVladimir Kotal		if (( $? == 0 )); then
291*02d26c39SVladimir Kotal			echo "directory '$WDIR' contains \"closed\" directory"
292*02d26c39SVladimir Kotal			return 1
293*02d26c39SVladimir Kotal		fi
294*02d26c39SVladimir Kotal	fi
295*02d26c39SVladimir Kotal
296*02d26c39SVladimir Kotal	# we have the URI for remote destination now so let's start the upload
297*02d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
298*02d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
299*02d26c39SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix}
300*02d26c39SVladimir Kotal			return $?
301*02d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
302*02d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
303*02d26c39SVladimir Kotal			return $?
304*02d26c39SVladimir Kotal		else
305*02d26c39SVladimir Kotal			echo "invalid upload URI ($remote_target)"
306*02d26c39SVladimir Kotal			return 1
307*02d26c39SVladimir Kotal		fi
308*02d26c39SVladimir Kotal	else
309*02d26c39SVladimir Kotal		# try rsync first and fallback to SSH in case it fails
310*02d26c39SVladimir Kotal		rsync_upload $dst_rsync
311*02d26c39SVladimir Kotal		if (( $? != 0 )); then
312*02d26c39SVladimir Kotal			echo "rsync upload failed, falling back to SSH"
313*02d26c39SVladimir Kotal			ssh_upload $dst_ssh
314*02d26c39SVladimir Kotal		fi
315*02d26c39SVladimir Kotal		return $?
316*02d26c39SVladimir Kotal	fi
317*02d26c39SVladimir Kotal
318*02d26c39SVladimir Kotal	return 0
319*02d26c39SVladimir Kotal}
320*02d26c39SVladimir Kotal
321daaffb31Sdp#
322daaffb31Sdp# input_cmd | html_quote | output_cmd
323daaffb31Sdp# or
324daaffb31Sdp# html_quote filename | output_cmd
3257c478bd9Sstevel@tonic-gate#
3267c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
3277c478bd9Sstevel@tonic-gate#
3287c478bd9Sstevel@tonic-gatehtml_quote()
3297c478bd9Sstevel@tonic-gate{
3307c478bd9Sstevel@tonic-gate	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
3317c478bd9Sstevel@tonic-gate}
3327c478bd9Sstevel@tonic-gate
333daaffb31Sdp#
334daaffb31Sdp# input_cmd | bug2url | output_cmd
335daaffb31Sdp#
336daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
337daaffb31Sdp#
338daaffb31Sdpbug2url()
3397c478bd9Sstevel@tonic-gate{
340daaffb31Sdp	sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
341daaffb31Sdp}
342daaffb31Sdp
3437c478bd9Sstevel@tonic-gate#
344daaffb31Sdp# input_cmd | sac2url | output_cmd
3457c478bd9Sstevel@tonic-gate#
346daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
347daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
348daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
349daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
3507c478bd9Sstevel@tonic-gate#
351daaffb31Sdpsac2url()
352daaffb31Sdp{
353e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
3540a30ef2cSstevel	    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'
355daaffb31Sdp	else
356daaffb31Sdp	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
357daaffb31Sdp	fi
358daaffb31Sdp}
359daaffb31Sdp
3607c478bd9Sstevel@tonic-gate#
361daaffb31Sdp# strip_unchanged <infile> | output_cmd
3627c478bd9Sstevel@tonic-gate#
363daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
364daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
3657c478bd9Sstevel@tonic-gate#
366daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
367daaffb31Sdp# identical lines are retained before and after the changed lines to
368daaffb31Sdp# provide some context.  The number of these lines is controlled by the
369cdf0c1d5Smjnelson# variable C in the $AWK script below.
370daaffb31Sdp#
371daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
372daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
373daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
374daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
375daaffb31Sdp#
376daaffb31Sdpstrip_unchanged()
377daaffb31Sdp{
378cdf0c1d5Smjnelson	$AWK '
379daaffb31Sdp	BEGIN	{ C = c = 20 }
380cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
381daaffb31Sdp		if (c > C) {
382daaffb31Sdp			c -= C
383daaffb31Sdp			inx = 0
384daaffb31Sdp			if (c > C) {
385cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
386daaffb31Sdp				inx = c % C
387daaffb31Sdp				c = C
388daaffb31Sdp			}
389daaffb31Sdp
390daaffb31Sdp			for (i = 0; i < c; i++)
391daaffb31Sdp				print ln[(inx + i) % C]
392daaffb31Sdp		}
393daaffb31Sdp		c = 0;
394daaffb31Sdp		print
395daaffb31Sdp		next
396daaffb31Sdp	}
397daaffb31Sdp	{	if (c >= C) {
398daaffb31Sdp			ln[c % C] = $0
399daaffb31Sdp			c++;
400daaffb31Sdp			next;
401daaffb31Sdp		}
402daaffb31Sdp		c++;
403daaffb31Sdp		print
404daaffb31Sdp	}
405cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
406daaffb31Sdp
407daaffb31Sdp	' $1
408daaffb31Sdp}
409daaffb31Sdp
410daaffb31Sdp#
411daaffb31Sdp# sdiff_to_html
412daaffb31Sdp#
413daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
414daaffb31Sdp# processes the diff output to present the files as an HTML document with
415daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
416daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
417daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
418daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
419daaffb31Sdp# e.g.
420daaffb31Sdp#
421daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
422daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
423daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
424daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
425daaffb31Sdp#          1234567</a> my bugid' > <file>.html
426daaffb31Sdp#
427daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
428daaffb31Sdp# in the webrev tree.
429daaffb31Sdp#
430daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
431daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
432daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
433daaffb31Sdp# the editing codes, e.g.
4347c478bd9Sstevel@tonic-gate#
4357c478bd9Sstevel@tonic-gate#      8c8
4367c478bd9Sstevel@tonic-gate#      57a61
4377c478bd9Sstevel@tonic-gate#      63c66,76
4387c478bd9Sstevel@tonic-gate#      68,93d80
4397c478bd9Sstevel@tonic-gate#      106d90
4407c478bd9Sstevel@tonic-gate#      108,110d91
4417c478bd9Sstevel@tonic-gate#
442daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
443daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
444daaffb31Sdp#  into something like this:
4457c478bd9Sstevel@tonic-gate#
4467c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
4477c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
448daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
4497c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
4507c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
4517c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
4527c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
4537c478bd9Sstevel@tonic-gate#        :               :
4547c478bd9Sstevel@tonic-gate#
455daaffb31Sdp#  This script is then run on the original source file to generate the
456daaffb31Sdp#  HTML that corresponds to the source file.
4577c478bd9Sstevel@tonic-gate#
458daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
459daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
460daaffb31Sdp#  notice that the changes are color-coded:
4617c478bd9Sstevel@tonic-gate#
4627c478bd9Sstevel@tonic-gate#   black     - unchanged lines
4637c478bd9Sstevel@tonic-gate#   blue      - changed lines
4647c478bd9Sstevel@tonic-gate#   bold blue - new lines
4657c478bd9Sstevel@tonic-gate#   brown     - deleted lines
4667c478bd9Sstevel@tonic-gate#
467daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
468daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
469daaffb31Sdp#  Teamware's filemerge tool.
470daaffb31Sdp#
471daaffb31Sdpsdiff_to_html()
472daaffb31Sdp{
4737c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
4747c478bd9Sstevel@tonic-gate
475daaffb31Sdp	TNAME=$3
476daaffb31Sdp	TPATH=$4
477daaffb31Sdp	COMMENT=$5
478daaffb31Sdp
4797c478bd9Sstevel@tonic-gate	#
4807c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
4817c478bd9Sstevel@tonic-gate	#
482cdf0c1d5Smjnelson	$AWK '
4837c478bd9Sstevel@tonic-gate	BEGIN	{
4847c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
485daaffb31Sdp		printf "function removed() "
486daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
487daaffb31Sdp		printf "function changed() "
488daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
489daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
4907c478bd9Sstevel@tonic-gate}
4917c478bd9Sstevel@tonic-gate	/^</	{next}
4927c478bd9Sstevel@tonic-gate	/^>/	{next}
4937c478bd9Sstevel@tonic-gate	/^---/	{next}
494daaffb31Sdp
4957c478bd9Sstevel@tonic-gate	{
4967c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
4977c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
4987c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
4997c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
5007c478bd9Sstevel@tonic-gate			if (n == 1)
5017c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
5027c478bd9Sstevel@tonic-gate			else
5037c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
5047c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
5057c478bd9Sstevel@tonic-gate			next
5067c478bd9Sstevel@tonic-gate		}
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
5097c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
5107c478bd9Sstevel@tonic-gate		s = r[1];
5117c478bd9Sstevel@tonic-gate		if (n == 1)
5127c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
5137c478bd9Sstevel@tonic-gate		else {
5147c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
5157c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
5167c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
5177c478bd9Sstevel@tonic-gate		}
5187c478bd9Sstevel@tonic-gate		next
5197c478bd9Sstevel@tonic-gate	}
5207c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
5217c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5227c478bd9Sstevel@tonic-gate		n1 = r[1]
5237c478bd9Sstevel@tonic-gate		n2 = r[2]
5247c478bd9Sstevel@tonic-gate		if (n == 1)
525daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
5267c478bd9Sstevel@tonic-gate		else
527daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
5287c478bd9Sstevel@tonic-gate		next
5297c478bd9Sstevel@tonic-gate	}
5307c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
5317c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5327c478bd9Sstevel@tonic-gate		n1 = r[1]
5337c478bd9Sstevel@tonic-gate		n2 = r[2]
5347c478bd9Sstevel@tonic-gate		final = n2
5357c478bd9Sstevel@tonic-gate		d1 = 0
5367c478bd9Sstevel@tonic-gate		if (n == 1)
537daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
5387c478bd9Sstevel@tonic-gate		else {
5397c478bd9Sstevel@tonic-gate			d1 = n2 - n1
540daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
5417c478bd9Sstevel@tonic-gate		}
5427c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
5437c478bd9Sstevel@tonic-gate		n1 = r[1]
5447c478bd9Sstevel@tonic-gate		n2 = r[2]
5457c478bd9Sstevel@tonic-gate		if (m > 1) {
5467c478bd9Sstevel@tonic-gate			d2  = n2 - n1
5477c478bd9Sstevel@tonic-gate			if (d2 > d1) {
5487c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
5497c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
5507c478bd9Sstevel@tonic-gate			}
5517c478bd9Sstevel@tonic-gate		}
5527c478bd9Sstevel@tonic-gate		printf "next}\n" ;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate		next
5557c478bd9Sstevel@tonic-gate	}
5567c478bd9Sstevel@tonic-gate	}
5577c478bd9Sstevel@tonic-gate
558daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
559daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate	#
5627c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
5637c478bd9Sstevel@tonic-gate	#
564cdf0c1d5Smjnelson	$AWK '
5657c478bd9Sstevel@tonic-gate	BEGIN	{
5667c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
567daaffb31Sdp		printf "function new() "
568daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
569daaffb31Sdp		printf "function changed() "
570daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
571daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
5727c478bd9Sstevel@tonic-gate	}
573daaffb31Sdp
5747c478bd9Sstevel@tonic-gate	/^</	{next}
5757c478bd9Sstevel@tonic-gate	/^>/	{next}
5767c478bd9Sstevel@tonic-gate	/^---/	{next}
577daaffb31Sdp
5787c478bd9Sstevel@tonic-gate	{
5797c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
5807c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
5817c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
5827c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
5837c478bd9Sstevel@tonic-gate			if (n == 1)
5847c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
5857c478bd9Sstevel@tonic-gate			else
5867c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
5877c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
5887c478bd9Sstevel@tonic-gate			next
5897c478bd9Sstevel@tonic-gate		}
5907c478bd9Sstevel@tonic-gate
5917c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
5927c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5937c478bd9Sstevel@tonic-gate		s = r[1];
5947c478bd9Sstevel@tonic-gate		if (n == 1)
5957c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
5967c478bd9Sstevel@tonic-gate		else {
5977c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
5987c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
5997c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6007c478bd9Sstevel@tonic-gate		}
6017c478bd9Sstevel@tonic-gate		next
6027c478bd9Sstevel@tonic-gate	}
6037c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6047c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6057c478bd9Sstevel@tonic-gate		n1 = r[1]
6067c478bd9Sstevel@tonic-gate		n2 = r[2]
6077c478bd9Sstevel@tonic-gate		if (n == 1)
608daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
6097c478bd9Sstevel@tonic-gate		else
610daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
6117c478bd9Sstevel@tonic-gate		next
6127c478bd9Sstevel@tonic-gate	}
6137c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
6147c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6157c478bd9Sstevel@tonic-gate		n1 = r[1]
6167c478bd9Sstevel@tonic-gate		n2 = r[2]
6177c478bd9Sstevel@tonic-gate		final = n2
6187c478bd9Sstevel@tonic-gate		d2 = 0;
6197c478bd9Sstevel@tonic-gate		if (n == 1) {
6207c478bd9Sstevel@tonic-gate			final = n1
621daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
6227c478bd9Sstevel@tonic-gate		} else {
6237c478bd9Sstevel@tonic-gate			d2 = n2 - n1
624daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
6257c478bd9Sstevel@tonic-gate		}
6267c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
6277c478bd9Sstevel@tonic-gate		n1 = r[1]
6287c478bd9Sstevel@tonic-gate		n2 = r[2]
6297c478bd9Sstevel@tonic-gate		if (m > 1) {
6307c478bd9Sstevel@tonic-gate			d1  = n2 - n1
6317c478bd9Sstevel@tonic-gate			if (d1 > d2) {
6327c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
6337c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
6347c478bd9Sstevel@tonic-gate			}
6357c478bd9Sstevel@tonic-gate		}
6367c478bd9Sstevel@tonic-gate		printf "next}\n" ;
6377c478bd9Sstevel@tonic-gate		next
6387c478bd9Sstevel@tonic-gate	}
6397c478bd9Sstevel@tonic-gate	}
640daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
6417c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
6427c478bd9Sstevel@tonic-gate
643daaffb31Sdp	#
644cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
645daaffb31Sdp	#
646cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
6477c478bd9Sstevel@tonic-gate
648cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
6497c478bd9Sstevel@tonic-gate
650daaffb31Sdp	#
651daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
652daaffb31Sdp	#
653daaffb31Sdp	print "$HTML<head>$STDHEAD"
654cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
655daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
656daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
657daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
658daaffb31Sdp	print "<table><tr valign=\"top\">"
659daaffb31Sdp	print "<td><pre>"
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
6627c478bd9Sstevel@tonic-gate
663daaffb31Sdp	print "</pre></td><td><pre>"
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
6667c478bd9Sstevel@tonic-gate
667daaffb31Sdp	print "</pre></td>"
668daaffb31Sdp	print "</tr></table>"
669daaffb31Sdp	print "</body></html>"
6707c478bd9Sstevel@tonic-gate
671daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
672daaffb31Sdp	    "$COMMENT"
6737c478bd9Sstevel@tonic-gate}
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate
676daaffb31Sdp#
677daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
678daaffb31Sdp#
679daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
680daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
681daaffb31Sdp# and then emit the main frame.  Content is placed into:
682daaffb31Sdp#
683daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
684daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
685daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
686daaffb31Sdp#
687daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
688daaffb31Sdp#
6897c478bd9Sstevel@tonic-gatefunction framed_sdiff
6907c478bd9Sstevel@tonic-gate{
6917c478bd9Sstevel@tonic-gate	typeset TNAME=$1
692daaffb31Sdp	typeset TPATH=$2
693daaffb31Sdp	typeset lhsfile=$3
694daaffb31Sdp	typeset rhsfile=$4
695daaffb31Sdp	typeset comments=$5
6967c478bd9Sstevel@tonic-gate	typeset RTOP
697daaffb31Sdp
6987c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
699daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
700daaffb31Sdp
701daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
702daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
703daaffb31Sdp
704daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
705cac38512Smjnelson	    <script type="text/javascript" src="$RTOP/ancnav.js"></script>
7067c478bd9Sstevel@tonic-gate	    </head>
707daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
708cac38512Smjnelson	    <a name="0"></a>
709cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
710daaffb31Sdp	EOF
711daaffb31Sdp
712daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
713daaffb31Sdp
714daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
715daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
716daaffb31Sdp
717daaffb31Sdp	close='</body></html>'
718daaffb31Sdp
719daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
720daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
721daaffb31Sdp
722daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
723daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
724daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
725daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
726daaffb31Sdp	  <frameset rows="*,60">
727daaffb31Sdp	    <frameset cols="50%,50%">
728cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
729cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
730daaffb31Sdp	    </frameset>
731daaffb31Sdp	  <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
732cac38512Smjnelson	   marginheight="0" name="nav"></frame>
733daaffb31Sdp	  <noframes>
734daaffb31Sdp            <body id="SUNWwebrev">
735daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
7367c478bd9Sstevel@tonic-gate	      and has the feature enabled.
737daaffb31Sdp            </body>
738daaffb31Sdp	  </noframes>
739daaffb31Sdp	  </frameset>
7407c478bd9Sstevel@tonic-gate	</html>
7417c478bd9Sstevel@tonic-gate	EOF
7427c478bd9Sstevel@tonic-gate}
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate
745daaffb31Sdp#
746daaffb31Sdp# fix_postscript
747daaffb31Sdp#
748daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
749daaffb31Sdp# 	- removing all extraneous headers/trailers
750daaffb31Sdp#	- making the page numbers right
751daaffb31Sdp#	- removing pages devoid of contents which confuse some
752daaffb31Sdp#	  postscript readers.
753daaffb31Sdp#
754daaffb31Sdp# From Casper.
755daaffb31Sdp#
756daaffb31Sdpfunction fix_postscript
7577c478bd9Sstevel@tonic-gate{
758daaffb31Sdp	infile=$1
7597c478bd9Sstevel@tonic-gate
760daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
7617c478bd9Sstevel@tonic-gate
762daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
763daaffb31Sdp	print "%%Orientation: Landscape\n";
7647c478bd9Sstevel@tonic-gate
765daaffb31Sdp	$pno = 0;
766daaffb31Sdp	$doprint = 1;
767daaffb31Sdp
768daaffb31Sdp	$page = "";
769daaffb31Sdp
770daaffb31Sdp	while (<>) {
771daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
772daaffb31Sdp
773daaffb31Sdp		if (/^%%Page:/) {
774daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
775daaffb31Sdp				# Header or single page containing text
776daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
777daaffb31Sdp				print $page;
778daaffb31Sdp				$pno++;
779daaffb31Sdp			} else {
780daaffb31Sdp				# Empty page, skip it.
7817c478bd9Sstevel@tonic-gate			}
782daaffb31Sdp			$page = "";
783daaffb31Sdp			$doprint = 1;
7847c478bd9Sstevel@tonic-gate			next;
7857c478bd9Sstevel@tonic-gate		}
7867c478bd9Sstevel@tonic-gate
787daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
788daaffb31Sdp		# %%Page of the next
789daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
790daaffb31Sdp		$page .= $_ if ($doprint);
7917c478bd9Sstevel@tonic-gate	}
7927c478bd9Sstevel@tonic-gate
793daaffb31Sdp	if ($page =~ /\)S/) {
794daaffb31Sdp		print "%%Page: ? $pno\n";
795daaffb31Sdp		print $page;
796daaffb31Sdp	} else {
797daaffb31Sdp		$pno--;
798daaffb31Sdp	}
799daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
800daaffb31SdpEOF
801daaffb31Sdp
80214983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
803daaffb31Sdp}
804daaffb31Sdp
805daaffb31Sdp
806daaffb31Sdp#
807daaffb31Sdp# input_cmd | insert_anchors | output_cmd
808daaffb31Sdp#
8097c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
810daaffb31Sdp# anchors.  These are used to drive the frames version of the
8117c478bd9Sstevel@tonic-gate# sdiffs output.
8127c478bd9Sstevel@tonic-gate#
8137c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
8147c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
8157c478bd9Sstevel@tonic-gate#
816daaffb31Sdp# The script detects changed lines as any line that has a "<span
817daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
818daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
8197c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
8207c478bd9Sstevel@tonic-gate# deleted.
8217c478bd9Sstevel@tonic-gate#
822daaffb31Sdpfunction insert_anchors
823daaffb31Sdp{
824cdf0c1d5Smjnelson	$AWK '
8257c478bd9Sstevel@tonic-gate	function ia() {
826daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
8277c478bd9Sstevel@tonic-gate	}
828daaffb31Sdp
8297c478bd9Sstevel@tonic-gate	BEGIN {
830daaffb31Sdp		anc=1;
8317c478bd9Sstevel@tonic-gate		inblock=1;
832daaffb31Sdp		printf "<pre>\n";
8337c478bd9Sstevel@tonic-gate	}
834daaffb31Sdp	NF == 0 || /^<span class=/ {
8357c478bd9Sstevel@tonic-gate		if (inblock == 0) {
8367c478bd9Sstevel@tonic-gate			ia();
8377c478bd9Sstevel@tonic-gate			inblock=1;
8387c478bd9Sstevel@tonic-gate		}
8397c478bd9Sstevel@tonic-gate		print;
8407c478bd9Sstevel@tonic-gate		next;
8417c478bd9Sstevel@tonic-gate	}
8427c478bd9Sstevel@tonic-gate	{
8437c478bd9Sstevel@tonic-gate		inblock=0;
8447c478bd9Sstevel@tonic-gate		print;
8457c478bd9Sstevel@tonic-gate	}
8467c478bd9Sstevel@tonic-gate	END {
8477c478bd9Sstevel@tonic-gate		ia();
848daaffb31Sdp
849daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
850daaffb31Sdp		printf "--- EOF ---</b>"
8517c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
852daaffb31Sdp		printf "</pre>"
853daaffb31Sdp		printf "<form name=\"eof\">";
854cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
855cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
856daaffb31Sdp		printf "</form>";
8577c478bd9Sstevel@tonic-gate	}
8587c478bd9Sstevel@tonic-gate	' $1
8597c478bd9Sstevel@tonic-gate}
8607c478bd9Sstevel@tonic-gate
8617c478bd9Sstevel@tonic-gate
862daaffb31Sdp#
863daaffb31Sdp# relative_dir
864daaffb31Sdp#
865daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
866daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
867daaffb31Sdp# this function would print "../../../../".
868daaffb31Sdp#
869daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
870daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
871daaffb31Sdp# is not relocatable.
872daaffb31Sdp#
873daaffb31Sdpfunction relative_dir
8747c478bd9Sstevel@tonic-gate{
875daaffb31Sdp	typeset cur="${1##$2?(/)}"
876daaffb31Sdp	typeset ret=""
877daaffb31Sdp	if [[ $2 == $cur ]]; then   # Should never happen.
878daaffb31Sdp		# Should never happen.
87914983201Sdp		print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
880daaffb31Sdp		print -u2 "to \"$2\".  Check input paths.  Framed webrev "
881daaffb31Sdp		print -u2 "will not be relocatable!"
882daaffb31Sdp		print $2
883daaffb31Sdp		return
884daaffb31Sdp	fi
885daaffb31Sdp
886daaffb31Sdp	while [[ -n ${cur} ]];
8877c478bd9Sstevel@tonic-gate	do
8887c478bd9Sstevel@tonic-gate		cur=${cur%%*(/)*([!/])}
889daaffb31Sdp		if [[ -z $ret ]]; then
890daaffb31Sdp			ret=".."
891daaffb31Sdp		else
8927c478bd9Sstevel@tonic-gate			ret="../$ret"
893daaffb31Sdp		fi
8947c478bd9Sstevel@tonic-gate	done
8957c478bd9Sstevel@tonic-gate	print $ret
8967c478bd9Sstevel@tonic-gate}
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate
899daaffb31Sdp#
900daaffb31Sdp# frame_nav_js
901daaffb31Sdp#
902daaffb31Sdp# Emit javascript for frame navigation
903daaffb31Sdp#
904daaffb31Sdpfunction frame_nav_js
9057c478bd9Sstevel@tonic-gate{
9067c478bd9Sstevel@tonic-gatecat << \EOF
9077c478bd9Sstevel@tonic-gatevar myInt;
9087c478bd9Sstevel@tonic-gatevar scrolling=0;
909daaffb31Sdpvar sfactor = 3;
9107c478bd9Sstevel@tonic-gatevar scount=10;
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gatefunction scrollByPix() {
9137c478bd9Sstevel@tonic-gate	if (scount<=0) {
9147c478bd9Sstevel@tonic-gate		sfactor*=1.2;
9157c478bd9Sstevel@tonic-gate		scount=10;
9167c478bd9Sstevel@tonic-gate	}
9177c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
9187c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
9197c478bd9Sstevel@tonic-gate	scount--;
9207c478bd9Sstevel@tonic-gate}
9217c478bd9Sstevel@tonic-gate
922daaffb31Sdpfunction scrollToAnc(num) {
923daaffb31Sdp
924daaffb31Sdp	// Update the value of the anchor in the form which we use as
925daaffb31Sdp	// storage for this value.  setAncValue() will take care of
926daaffb31Sdp	// correcting for overflow and underflow of the value and return
927daaffb31Sdp	// us the new value.
928daaffb31Sdp	num = setAncValue(num);
929daaffb31Sdp
930daaffb31Sdp	// Set location and scroll back a little to expose previous
931daaffb31Sdp	// lines.
932daaffb31Sdp	//
933daaffb31Sdp	// Note that this could be improved: it is possible although
934daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
935daaffb31Sdp	// scroll to that location directly.
936daaffb31Sdp	//
9377c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
9387c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
939daaffb31Sdp
9407c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
9417c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
9427c478bd9Sstevel@tonic-gate}
9437c478bd9Sstevel@tonic-gate
944daaffb31Sdpfunction getAncValue()
945daaffb31Sdp{
946daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
947daaffb31Sdp}
948daaffb31Sdp
949daaffb31Sdpfunction setAncValue(val)
950daaffb31Sdp{
951daaffb31Sdp	if (val <= 0) {
952daaffb31Sdp		val = 0;
953daaffb31Sdp		parent.nav.document.diff.real.value = val;
954daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
955daaffb31Sdp		return (val);
956daaffb31Sdp	}
957daaffb31Sdp
958daaffb31Sdp	//
959daaffb31Sdp	// The way we compute the max anchor value is to stash it
960daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
961daaffb31Sdp	// on each side, so we pluck from the left.
962daaffb31Sdp	//
963daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
964daaffb31Sdp	if (val < maxval) {
965daaffb31Sdp		parent.nav.document.diff.real.value = val;
966daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
967daaffb31Sdp		return (val);
968daaffb31Sdp	}
969daaffb31Sdp
970daaffb31Sdp	// this must be: val >= maxval
971daaffb31Sdp	val = maxval;
972daaffb31Sdp	parent.nav.document.diff.real.value = val;
973daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
974daaffb31Sdp	return (val);
975daaffb31Sdp}
976daaffb31Sdp
9777c478bd9Sstevel@tonic-gatefunction stopScroll() {
9787c478bd9Sstevel@tonic-gate	if (scrolling==1) {
9797c478bd9Sstevel@tonic-gate		clearInterval(myInt);
9807c478bd9Sstevel@tonic-gate		scrolling=0;
9817c478bd9Sstevel@tonic-gate	}
9827c478bd9Sstevel@tonic-gate}
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gatefunction startScroll() {
9857c478bd9Sstevel@tonic-gate	stopScroll();
9867c478bd9Sstevel@tonic-gate	scrolling=1;
9877c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
9887c478bd9Sstevel@tonic-gate}
9897c478bd9Sstevel@tonic-gate
9907c478bd9Sstevel@tonic-gatefunction handlePress(b) {
991daaffb31Sdp
9927c478bd9Sstevel@tonic-gate	switch (b) {
9937c478bd9Sstevel@tonic-gate	    case 1 :
994daaffb31Sdp		scrollToAnc(-1);
9957c478bd9Sstevel@tonic-gate		break;
9967c478bd9Sstevel@tonic-gate	    case 2 :
997daaffb31Sdp		scrollToAnc(getAncValue() - 1);
9987c478bd9Sstevel@tonic-gate		break;
9997c478bd9Sstevel@tonic-gate	    case 3 :
10007c478bd9Sstevel@tonic-gate		sfactor=-3;
10017c478bd9Sstevel@tonic-gate		startScroll();
10027c478bd9Sstevel@tonic-gate		break;
10037c478bd9Sstevel@tonic-gate	    case 4 :
10047c478bd9Sstevel@tonic-gate		sfactor=3;
10057c478bd9Sstevel@tonic-gate		startScroll();
10067c478bd9Sstevel@tonic-gate		break;
10077c478bd9Sstevel@tonic-gate	    case 5 :
1008daaffb31Sdp		scrollToAnc(getAncValue() + 1);
10097c478bd9Sstevel@tonic-gate		break;
10107c478bd9Sstevel@tonic-gate	    case 6 :
1011daaffb31Sdp		scrollToAnc(999999);
10127c478bd9Sstevel@tonic-gate		break;
10137c478bd9Sstevel@tonic-gate	}
10147c478bd9Sstevel@tonic-gate}
10157c478bd9Sstevel@tonic-gate
10167c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
10177c478bd9Sstevel@tonic-gate	stopScroll();
10187c478bd9Sstevel@tonic-gate}
10197c478bd9Sstevel@tonic-gate
1020daaffb31Sdpfunction keypress(ev) {
1021daaffb31Sdp	var keynum;
1022daaffb31Sdp	var keychar;
1023daaffb31Sdp
1024daaffb31Sdp	if (window.event) { // IE
1025daaffb31Sdp		keynum = ev.keyCode;
1026daaffb31Sdp	} else if (ev.which) { // non-IE
1027daaffb31Sdp		keynum = ev.which;
1028daaffb31Sdp	}
1029daaffb31Sdp
1030daaffb31Sdp	keychar = String.fromCharCode(keynum);
1031daaffb31Sdp
1032daaffb31Sdp	if (keychar == "k") {
1033daaffb31Sdp		handlePress(2);
1034daaffb31Sdp		return (0);
1035daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1036daaffb31Sdp		handlePress(5);
1037daaffb31Sdp		return (0);
1038daaffb31Sdp	}
1039daaffb31Sdp	return (1);
1040daaffb31Sdp}
1041daaffb31Sdp
10427c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1043daaffb31Sdp	val = parent.nav.document.diff.display.value;
1044daaffb31Sdp	if (val == "EOF") {
1045daaffb31Sdp		scrollToAnc(999999);
1046daaffb31Sdp		return;
1047daaffb31Sdp	}
1048daaffb31Sdp
1049daaffb31Sdp	if (val == "BOF") {
1050daaffb31Sdp		scrollToAnc(0);
1051daaffb31Sdp		return;
1052daaffb31Sdp	}
1053daaffb31Sdp
1054daaffb31Sdp        i=parseInt(val);
10557c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1056daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
10577c478bd9Sstevel@tonic-gate        } else {
1058daaffb31Sdp                scrollToAnc(i);
10597c478bd9Sstevel@tonic-gate        }
10607c478bd9Sstevel@tonic-gate        return false;
10617c478bd9Sstevel@tonic-gate}
10627c478bd9Sstevel@tonic-gate
1063daaffb31SdpEOF
1064daaffb31Sdp}
1065daaffb31Sdp
1066daaffb31Sdp#
1067daaffb31Sdp# frame_navigation
1068daaffb31Sdp#
1069daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1070daaffb31Sdp#
1071daaffb31Sdpfunction frame_navigation
1072daaffb31Sdp{
1073daaffb31Sdp	print "$HTML<head>$STDHEAD"
1074daaffb31Sdp
1075daaffb31Sdp	cat << \EOF
1076daaffb31Sdp<title>Anchor Navigation</title>
1077daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1078daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1079daaffb31Sdp
1080daaffb31Sdp<style type="text/css">
1081daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1082daaffb31Sdp		    background-color: #eee; text-align: center;
1083daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1084daaffb31Sdp    div.button a { font-weight: bold; color: black }
1085daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1086daaffb31Sdp</style>
1087daaffb31SdpEOF
1088daaffb31Sdp
1089cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1090daaffb31Sdp
1091daaffb31Sdp	cat << \EOF
10927c478bd9Sstevel@tonic-gate</head>
1093daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1094daaffb31Sdp	onkeypress="keypress(event);">
10957c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
10967c478bd9Sstevel@tonic-gate      <center>
1097cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
10987c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
10997c478bd9Sstevel@tonic-gate      </center>
11007c478bd9Sstevel@tonic-gate    </noscript>
11017c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1102daaffb31Sdp	<tr>
1103daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1104daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1105daaffb31Sdp          at right</td>
1106daaffb31Sdp	  <td align="center" valign="top" width="50%">
11077c478bd9Sstevel@tonic-gate	    <div class="button">
1108daaffb31Sdp	      <table border="0" align="center">
1109daaffb31Sdp                  <tr>
1110daaffb31Sdp		    <td>
11117c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
11127c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
11137c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
11147c478bd9Sstevel@tonic-gate			 onClick="return false;"
11157c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1116daaffb31Sdp		    <td>
11177c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
11187c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
11197c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
11207c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1121daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1122daaffb31Sdp		    <td>
11237c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
11247c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
11257c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
11267c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
11277c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
11287c478bd9Sstevel@tonic-gate		    </td></tr>
1129daaffb31Sdp
11307c478bd9Sstevel@tonic-gate		  <tr>
1131daaffb31Sdp		    <td>
11327c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
11337c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
11347c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
11357c478bd9Sstevel@tonic-gate			 onClick="return false;"
11367c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1137daaffb31Sdp		    <td>
11387c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
11397c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
11407c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
11417c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1142daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1143daaffb31Sdp		    <td>
11447c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
11457c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
11467c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
11477c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
11487c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1149daaffb31Sdp		  </tr>
1150daaffb31Sdp              </table>
1151daaffb31Sdp	    </div>
1152daaffb31Sdp	  </td>
11537c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1154daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1155cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1156cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
11577c478bd9Sstevel@tonic-gate	    </form>
11587c478bd9Sstevel@tonic-gate	  </th>
1159daaffb31Sdp	</tr>
11607c478bd9Sstevel@tonic-gate    </table>
11617c478bd9Sstevel@tonic-gate  </body>
11627c478bd9Sstevel@tonic-gate</html>
11637c478bd9Sstevel@tonic-gateEOF
11647c478bd9Sstevel@tonic-gate}
11657c478bd9Sstevel@tonic-gate
11667c478bd9Sstevel@tonic-gate
1167daaffb31Sdp
1168daaffb31Sdp#
1169daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1170daaffb31Sdp#
1171daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1172daaffb31Sdp# context or unified diffs.
1173daaffb31Sdp#
11747c478bd9Sstevel@tonic-gatediff_to_html()
11757c478bd9Sstevel@tonic-gate{
11767c478bd9Sstevel@tonic-gate	TNAME=$1
1177daaffb31Sdp	TPATH=$2
1178daaffb31Sdp	DIFFTYPE=$3
1179daaffb31Sdp	COMMENT=$4
1180daaffb31Sdp
1181daaffb31Sdp	print "$HTML<head>$STDHEAD"
1182daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1183daaffb31Sdp
1184daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1185daaffb31Sdp		print "$UDIFFCSS"
1186daaffb31Sdp	fi
1187daaffb31Sdp
1188daaffb31Sdp	cat <<-EOF
1189daaffb31Sdp	</head>
1190daaffb31Sdp	<body id="SUNWwebrev">
1191daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1192daaffb31Sdp	<pre>$COMMENT</pre>
1193daaffb31Sdp        <pre>
1194daaffb31Sdp	EOF
11957c478bd9Sstevel@tonic-gate
1196cdf0c1d5Smjnelson	html_quote | $AWK '
1197daaffb31Sdp	/^--- new/	{ next }
1198daaffb31Sdp	/^\+\+\+ new/	{ next }
1199daaffb31Sdp	/^--- old/	{ next }
1200daaffb31Sdp	/^\*\*\* old/	{ next }
1201daaffb31Sdp	/^\*\*\*\*/	{ next }
12027c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1203cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1204daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1205daaffb31Sdp			  next}
1206daaffb31Sdp
1207cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1208daaffb31Sdp			  next}
1209daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1210daaffb31Sdp			  next}
1211daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1212daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1213daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1214daaffb31Sdp			{printf "%s\n", $0; next}
12157c478bd9Sstevel@tonic-gate	'
1216daaffb31Sdp
1217daaffb31Sdp	print "</pre></body></html>\n"
12187c478bd9Sstevel@tonic-gate}
12197c478bd9Sstevel@tonic-gate
12207c478bd9Sstevel@tonic-gate
1221daaffb31Sdp#
1222daaffb31Sdp# source_to_html { new | old } <filename>
1223daaffb31Sdp#
1224daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1225daaffb31Sdp#
12267c478bd9Sstevel@tonic-gatesource_to_html()
12277c478bd9Sstevel@tonic-gate{
12287c478bd9Sstevel@tonic-gate	WHICH=$1
12297c478bd9Sstevel@tonic-gate	TNAME=$2
12307c478bd9Sstevel@tonic-gate
1231daaffb31Sdp	print "$HTML<head>$STDHEAD"
1232cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1233daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1234daaffb31Sdp	print "<pre>"
1235cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1236daaffb31Sdp	print "</pre></body></html>"
12377c478bd9Sstevel@tonic-gate}
12387c478bd9Sstevel@tonic-gate
1239daaffb31Sdp#
1240cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1241daaffb31Sdp#
1242daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1243daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1244daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1245daaffb31Sdp# delta in that list (the first delta unique to the child).
12467c478bd9Sstevel@tonic-gate#
12477c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1248daaffb31Sdp#
1249daaffb31Sdpcomments_from_teamware()
12507c478bd9Sstevel@tonic-gate{
1251daaffb31Sdp	fmt=$1
1252daaffb31Sdp	pfile=$PWS/$2
1253daaffb31Sdp	cfile=$CWS/$3
12547c478bd9Sstevel@tonic-gate
1255cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1256cdf0c1d5Smjnelson		pfile=$RWS/$2
1257cdf0c1d5Smjnelson	fi
1258cdf0c1d5Smjnelson
1259daaffb31Sdp	if [[ -f $pfile ]]; then
1260cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
12617c478bd9Sstevel@tonic-gate	else
12627c478bd9Sstevel@tonic-gate		psid=1.1
12637c478bd9Sstevel@tonic-gate	fi
12647c478bd9Sstevel@tonic-gate
1265cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
12667c478bd9Sstevel@tonic-gate	N=${#sids[@]}
12677c478bd9Sstevel@tonic-gate
1268daaffb31Sdp	nawkprg='
1269daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1270daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1271daaffb31Sdp		NF == 0u	{ continue }
1272daaffb31Sdp		{if (p==0) continue; print $0 }'
1273daaffb31Sdp
12747c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
12757c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
12767c478bd9Sstevel@tonic-gate
1277daaffb31Sdp		if [[ $fmt == "text" ]]; then
1278cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1279cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1280daaffb31Sdp			return
1281daaffb31Sdp		fi
1282daaffb31Sdp
1283cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1284cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
12857c478bd9Sstevel@tonic-gate	fi
12867c478bd9Sstevel@tonic-gate}
12877c478bd9Sstevel@tonic-gate
1288daaffb31Sdp#
1289cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1290daaffb31Sdp#
1291cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1292cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1293cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1294cdf0c1d5Smjnelson# are turned into URLs.
1295cdf0c1d5Smjnelson#
1296cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1297daaffb31Sdp#
1298daaffb31Sdpcomments_from_wx()
12997c478bd9Sstevel@tonic-gate{
1300daaffb31Sdp	typeset fmt=$1
1301daaffb31Sdp	typeset p=$2
13027c478bd9Sstevel@tonic-gate
1303cdf0c1d5Smjnelson	comm=`$AWK '
1304daaffb31Sdp	$1 == "'$p'" {
13057c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
13067c478bd9Sstevel@tonic-gate		getline
13077c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
13087c478bd9Sstevel@tonic-gate		exit
1309daaffb31Sdp	}' < $wxfile`
1310daaffb31Sdp
1311cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1312cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1313cdf0c1d5Smjnelson	fi
1314cdf0c1d5Smjnelson
1315daaffb31Sdp	if [[ $fmt == "text" ]]; then
1316cdf0c1d5Smjnelson		print -- "$comm"
1317daaffb31Sdp		return
1318daaffb31Sdp	fi
1319daaffb31Sdp
1320cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1321cdf0c1d5Smjnelson
13227c478bd9Sstevel@tonic-gate}
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate#
1325daaffb31Sdp# getcomments {text|html} filepath parentpath
1326daaffb31Sdp#
1327daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1328daaffb31Sdp#
1329daaffb31Sdpgetcomments()
1330daaffb31Sdp{
1331daaffb31Sdp	typeset fmt=$1
1332daaffb31Sdp	typeset p=$2
1333daaffb31Sdp	typeset pp=$3
13347c478bd9Sstevel@tonic-gate
13353df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
13363df69ef3SDarren Moffat		return
13373df69ef3SDarren Moffat	fi
1338cdf0c1d5Smjnelson	#
1339cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1340cdf0c1d5Smjnelson	# will be used there, too
1341cdf0c1d5Smjnelson	#
1342daaffb31Sdp	if [[ -n $wxfile ]]; then
1343daaffb31Sdp		comments_from_wx $fmt $p
1344daaffb31Sdp	else
1345daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1346daaffb31Sdp			comments_from_teamware $fmt $pp $p
1347daaffb31Sdp		fi
1348daaffb31Sdp	fi
1349daaffb31Sdp}
1350daaffb31Sdp
1351daaffb31Sdp#
1352daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1353daaffb31Sdp#
1354daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1355daaffb31Sdp#
1356daaffb31Sdpfunction printCI
1357daaffb31Sdp{
1358daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1359daaffb31Sdp	typeset str
1360daaffb31Sdp	if (( tot == 1 )); then
1361daaffb31Sdp		str="line"
1362daaffb31Sdp	else
1363daaffb31Sdp		str="lines"
1364daaffb31Sdp	fi
1365daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1366daaffb31Sdp	    $tot $str $ins $del $mod $unc
1367daaffb31Sdp}
1368daaffb31Sdp
1369daaffb31Sdp
1370daaffb31Sdp#
1371daaffb31Sdp# difflines <oldfile> <newfile>
1372daaffb31Sdp#
1373daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1374daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1375daaffb31Sdp#
13767c478bd9Sstevel@tonic-gatefunction difflines
13777c478bd9Sstevel@tonic-gate{
1378daaffb31Sdp	integer tot mod del ins unc err
13797c478bd9Sstevel@tonic-gate	typeset filename
13807c478bd9Sstevel@tonic-gate
1381cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1382daaffb31Sdp	# Change range of lines: N,Nc
13837c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
13847c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
13857c478bd9Sstevel@tonic-gate		if (n != 2) {
13867c478bd9Sstevel@tonic-gate		    error=2
13877c478bd9Sstevel@tonic-gate		    exit;
13887c478bd9Sstevel@tonic-gate		}
1389daaffb31Sdp		#
1390daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1391daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1392daaffb31Sdp		#
13937c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1394daaffb31Sdp
1395daaffb31Sdp		#
1396daaffb31Sdp		# Now count replacement lines: each represents a change instead
1397daaffb31Sdp		# of a delete, so increment c and decrement r.
1398daaffb31Sdp		#
13997c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
14007c478bd9Sstevel@tonic-gate			c++;
14017c478bd9Sstevel@tonic-gate			r--;
14027c478bd9Sstevel@tonic-gate		}
1403daaffb31Sdp		#
1404daaffb31Sdp		# If there were more replacement lines than original lines,
1405daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1406daaffb31Sdp		# but there are r changes that should be counted as adds, and
1407daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1408daaffb31Sdp		#
14097c478bd9Sstevel@tonic-gate		if (r < 0) {
14107c478bd9Sstevel@tonic-gate			a-=r;
14117c478bd9Sstevel@tonic-gate			c+=r;
14127c478bd9Sstevel@tonic-gate		}
1413daaffb31Sdp
1414daaffb31Sdp		#
1415daaffb31Sdp		# If there were more original lines than replacement lines, then
1416daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1417daaffb31Sdp		#
14187c478bd9Sstevel@tonic-gate		if (r > 0) {
14197c478bd9Sstevel@tonic-gate			d+=r;
14207c478bd9Sstevel@tonic-gate		}
14217c478bd9Sstevel@tonic-gate		next;
14227c478bd9Sstevel@tonic-gate	}
14237c478bd9Sstevel@tonic-gate
1424daaffb31Sdp	# Change lines: Nc
14257c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1426daaffb31Sdp		# The first line is a replacement; any more are additions.
14277c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
14287c478bd9Sstevel@tonic-gate			c++;
14297c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
14307c478bd9Sstevel@tonic-gate		}
14317c478bd9Sstevel@tonic-gate		next;
14327c478bd9Sstevel@tonic-gate	}
14337c478bd9Sstevel@tonic-gate
1434daaffb31Sdp	# Add lines: both Na and N,Na
14357c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
14367c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
14377c478bd9Sstevel@tonic-gate		next;
14387c478bd9Sstevel@tonic-gate	}
14397c478bd9Sstevel@tonic-gate
1440daaffb31Sdp	# Delete range of lines: N,Nd
14417c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
14427c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
14437c478bd9Sstevel@tonic-gate		if (n != 2) {
14447c478bd9Sstevel@tonic-gate			error=2
14457c478bd9Sstevel@tonic-gate			exit;
14467c478bd9Sstevel@tonic-gate		}
1447daaffb31Sdp		#
1448daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1449daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1450daaffb31Sdp		#
14517c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
14527c478bd9Sstevel@tonic-gate		d+=r;
14537c478bd9Sstevel@tonic-gate		next;
14547c478bd9Sstevel@tonic-gate	}
14557c478bd9Sstevel@tonic-gate
1456daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
14577c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
14587c478bd9Sstevel@tonic-gate
1459daaffb31Sdp	# Should not get here!
14607c478bd9Sstevel@tonic-gate	{
14617c478bd9Sstevel@tonic-gate		error=1;
14627c478bd9Sstevel@tonic-gate		exit;
14637c478bd9Sstevel@tonic-gate	}
14647c478bd9Sstevel@tonic-gate
1465daaffb31Sdp	# Finish off - print results
14667c478bd9Sstevel@tonic-gate	END {
1467daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
14687c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
14697c478bd9Sstevel@tonic-gate	}' )
14707c478bd9Sstevel@tonic-gate
1471cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
14727c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1473daaffb31Sdp		print "Unexpected Error occurred reading" \
1474daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1475daaffb31Sdp		return
1476daaffb31Sdp	fi
1477daaffb31Sdp
14787c478bd9Sstevel@tonic-gate	# Accumulate totals
14797c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1480daaffb31Sdp	(( TMOD += mod ))
14817c478bd9Sstevel@tonic-gate	(( TDEL += del ))
14827c478bd9Sstevel@tonic-gate	(( TINS += ins ))
14837c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1484cdf0c1d5Smjnelson	unc=`wc -l < $1`
14857c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1486daaffb31Sdp		(( unc -= del + mod ))
14877c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
14887c478bd9Sstevel@tonic-gate	fi
14897c478bd9Sstevel@tonic-gate	# print summary
1490daaffb31Sdp	print "<span class=\"lineschanged\">"
1491daaffb31Sdp	printCI $tot $ins $del $mod $unc
1492daaffb31Sdp	print "</span>"
14937c478bd9Sstevel@tonic-gate}
14947c478bd9Sstevel@tonic-gate
1495daaffb31Sdp
14967c478bd9Sstevel@tonic-gate#
1497daaffb31Sdp# flist_from_wx
1498daaffb31Sdp#
1499daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1500daaffb31Sdp# Sets the global 'wxfile' variable.
1501daaffb31Sdp#
1502daaffb31Sdpfunction flist_from_wx
15037c478bd9Sstevel@tonic-gate{
1504daaffb31Sdp	typeset argfile=$1
1505daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1506daaffb31Sdp		#
1507daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1508daaffb31Sdp		# because the webrev does a "cd" later on.
1509daaffb31Sdp		#
1510daaffb31Sdp		wxfile=$PWD/$argfile
15117c478bd9Sstevel@tonic-gate	else
1512daaffb31Sdp		wxfile=$argfile
15137c478bd9Sstevel@tonic-gate	fi
15147c478bd9Sstevel@tonic-gate
1515cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
15167c478bd9Sstevel@tonic-gate	  while (getline) {
15177c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
15187c478bd9Sstevel@tonic-gate		if (c > 0) print
15197c478bd9Sstevel@tonic-gate	  }
1520daaffb31Sdp	}' $wxfile > $FLIST
15217c478bd9Sstevel@tonic-gate
1522daaffb31Sdp	print " Done."
1523daaffb31Sdp}
15247c478bd9Sstevel@tonic-gate
1525daaffb31Sdp#
1526daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1527daaffb31Sdp#
1528daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1529daaffb31Sdp# names may come from the "update/create" messages and others from the
1530daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1531daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1532daaffb31Sdp# -n as well, but remove them if they are already defined.
1533daaffb31Sdp#
1534daaffb31Sdpfunction flist_from_teamware
1535daaffb31Sdp{
1536cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1537daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1538daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1539daaffb31Sdp			    "valid teamware workspace"
15407c478bd9Sstevel@tonic-gate			exit 1
15417c478bd9Sstevel@tonic-gate		fi
1542daaffb31Sdp		parent_args="-p $codemgr_parent"
15437c478bd9Sstevel@tonic-gate	fi
15447c478bd9Sstevel@tonic-gate
1545daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
15467c478bd9Sstevel@tonic-gate
1547daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1548cdf0c1d5Smjnelson	    $AWK '
1549daaffb31Sdp		/^update:|^create:/	{print $2}
1550daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1551daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1552daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1553daaffb31Sdp		NF == 0			{p=0 ; continue}
1554daaffb31Sdp		/^rename/		{old=$3}
1555daaffb31Sdp		$1 == "to:"		{print $2, old}
1556daaffb31Sdp		/^"/			{continue}
1557daaffb31Sdp		p == 1			{print $1}' |
1558daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
15597c478bd9Sstevel@tonic-gate
1560daaffb31Sdp	print " Done."
1561daaffb31Sdp}
1562daaffb31Sdp
1563cdf0c1d5Smjnelson#
1564cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1565cdf0c1d5Smjnelson#
1566cdf0c1d5Smjnelsonfunction hg_active_wxfile
1567cdf0c1d5Smjnelson{
1568cdf0c1d5Smjnelson	typeset child=$1
1569cdf0c1d5Smjnelson	typeset parent=$2
1570cdf0c1d5Smjnelson
1571cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
15729a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1573cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1574cdf0c1d5Smjnelson}
1575cdf0c1d5Smjnelson
1576cdf0c1d5Smjnelson#
1577cdf0c1d5Smjnelson# flist_from_mercurial
1578cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1579cdf0c1d5Smjnelson# flist_from_wx
1580cdf0c1d5Smjnelson#
1581cdf0c1d5Smjnelsonfunction flist_from_mercurial
1582cdf0c1d5Smjnelson{
1583cdf0c1d5Smjnelson	typeset child=$1
1584cdf0c1d5Smjnelson	typeset parent=$2
1585cdf0c1d5Smjnelson
1586cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1587cdf0c1d5Smjnelson
1588cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1589cdf0c1d5Smjnelson		print		# Blank line for the \c above
1590cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1591cdf0c1d5Smjnelson		exit 1
1592cdf0c1d5Smjnelson	fi
1593cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1594cdf0c1d5Smjnelson
1595cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1596cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1597cdf0c1d5Smjnelson}
1598cdf0c1d5Smjnelson
1599cdf0c1d5Smjnelson#
1600cdf0c1d5Smjnelson# flist_from_subversion
1601cdf0c1d5Smjnelson#
1602cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1603cdf0c1d5Smjnelson#
1604cdf0c1d5Smjnelsonfunction flist_from_subversion
1605cdf0c1d5Smjnelson{
1606cdf0c1d5Smjnelson	CWS=$1
1607cdf0c1d5Smjnelson	OLDPWD=$2
1608cdf0c1d5Smjnelson
1609cdf0c1d5Smjnelson	cd $CWS
1610cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1611cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1612cdf0c1d5Smjnelson	print -u2 " Done."
1613cdf0c1d5Smjnelson	cd $OLDPWD
1614cdf0c1d5Smjnelson}
1615cdf0c1d5Smjnelson
1616daaffb31Sdpfunction env_from_flist
1617daaffb31Sdp{
1618daaffb31Sdp	[[ -r $FLIST ]] || return
1619daaffb31Sdp
1620daaffb31Sdp	#
1621daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1622daaffb31Sdp	# list.  Then copy those into our local versions of those
1623daaffb31Sdp	# variables if they have not been set already.
1624daaffb31Sdp	#
1625*02d26c39SVladimir Kotal	eval `sed -e "s/#.*$//" $FLIST | $GREP = `
16267c478bd9Sstevel@tonic-gate
1627cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1628cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1629cdf0c1d5Smjnelson		export CODEMGR_WS
1630cdf0c1d5Smjnelson	fi
16317c478bd9Sstevel@tonic-gate
1632daaffb31Sdp	#
1633daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1634daaffb31Sdp	#
1635cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1636daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1637cdf0c1d5Smjnelson		export CODEMGR_PARENT
1638daaffb31Sdp	fi
1639daaffb31Sdp}
1640daaffb31Sdp
164114983201Sdpfunction look_for_prog
164214983201Sdp{
164314983201Sdp	typeset path
164414983201Sdp	typeset ppath
164514983201Sdp	typeset progname=$1
164614983201Sdp
164714983201Sdp	ppath=$PATH
164814983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
164914983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1650cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
165114983201Sdp
165214983201Sdp	PATH=$ppath prog=`whence $progname`
165314983201Sdp	if [[ -n $prog ]]; then
165414983201Sdp		print $prog
165514983201Sdp	fi
165614983201Sdp}
165714983201Sdp
1658cdf0c1d5Smjnelsonfunction get_file_mode
1659cdf0c1d5Smjnelson{
1660cdf0c1d5Smjnelson	$PERL -e '
1661cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1662cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1663cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1664cdf0c1d5Smjnelson			exit 0;
1665cdf0c1d5Smjnelson		} else {
1666cdf0c1d5Smjnelson			exit 1;
1667cdf0c1d5Smjnelson		}
1668cdf0c1d5Smjnelson	    ' $1
1669cdf0c1d5Smjnelson}
1670cdf0c1d5Smjnelson
1671cdf0c1d5Smjnelsonfunction build_old_new_teamware
1672cdf0c1d5Smjnelson{
1673cdf0c1d5Smjnelson	typeset olddir="$1"
1674cdf0c1d5Smjnelson	typeset newdir="$2"
1675cdf0c1d5Smjnelson
1676cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1677cdf0c1d5Smjnelson	# get a readonly copy.
1678cdf0c1d5Smjnelson
1679cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1680cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1681cdf0c1d5Smjnelson	fi
1682cdf0c1d5Smjnelson
1683cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1684cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1685cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1686cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1687cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1688cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1689cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1690cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1691cdf0c1d5Smjnelson	# permissions that would result after check in.
1692cdf0c1d5Smjnelson
1693cdf0c1d5Smjnelson	#
1694cdf0c1d5Smjnelson	# Snag new version of file.
1695cdf0c1d5Smjnelson	#
1696cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1697cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1698cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1699cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1700cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1701cdf0c1d5Smjnelson	fi
1702cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1703cdf0c1d5Smjnelson
1704cdf0c1d5Smjnelson	#
1705cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1706cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1707cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1708cdf0c1d5Smjnelson	#
1709cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1710cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1711cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1712cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1713cdf0c1d5Smjnelson		# the old file.
1714cdf0c1d5Smjnelson
1715cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1716cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1717cdf0c1d5Smjnelson	else
1718cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1719cdf0c1d5Smjnelson			real_parent=$PWS
1720cdf0c1d5Smjnelson		else
1721cdf0c1d5Smjnelson			real_parent=$RWS
1722cdf0c1d5Smjnelson		fi
1723cdf0c1d5Smjnelson
1724cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1725cdf0c1d5Smjnelson
1726cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1727cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1728cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1729cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1730cdf0c1d5Smjnelson			else
1731cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1732cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1733cdf0c1d5Smjnelson			fi
1734cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1735cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1736cdf0c1d5Smjnelson		fi
1737cdf0c1d5Smjnelson	fi
1738cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1739cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1740cdf0c1d5Smjnelson	fi
1741cdf0c1d5Smjnelson}
1742cdf0c1d5Smjnelson
1743cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1744cdf0c1d5Smjnelson{
1745cdf0c1d5Smjnelson	typeset olddir="$1"
1746cdf0c1d5Smjnelson	typeset newdir="$2"
1747cdf0c1d5Smjnelson	typeset old_mode=
1748cdf0c1d5Smjnelson	typeset new_mode=
1749cdf0c1d5Smjnelson	typeset file
1750cdf0c1d5Smjnelson
1751cdf0c1d5Smjnelson	#
1752cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1753cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1754cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1755cdf0c1d5Smjnelson	#
1756cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1757cdf0c1d5Smjnelson		file="$PF"
1758cdf0c1d5Smjnelson	else
1759cdf0c1d5Smjnelson		file="$PDIR/$PF"
1760cdf0c1d5Smjnelson	fi
1761cdf0c1d5Smjnelson	file=`echo $file | sed 's#/#\\\/#g'`
1762cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1763cdf0c1d5Smjnelson	old_mode=`sed -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1764cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1765cdf0c1d5Smjnelson
1766cdf0c1d5Smjnelson	#
1767cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1768cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1769cdf0c1d5Smjnelson	#
1770cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1771cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1772cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1773cdf0c1d5Smjnelson			new_mode=755
1774cdf0c1d5Smjnelson		else
1775cdf0c1d5Smjnelson			new_mode=644
1776cdf0c1d5Smjnelson		fi
1777cdf0c1d5Smjnelson	fi
1778cdf0c1d5Smjnelson
1779cdf0c1d5Smjnelson	#
1780cdf0c1d5Smjnelson	# new version of the file.
1781cdf0c1d5Smjnelson	#
1782cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1783cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1784cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1785cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1786cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1787cdf0c1d5Smjnelson		else
1788cdf0c1d5Smjnelson			# should never happen
1789cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1790cdf0c1d5Smjnelson		fi
1791cdf0c1d5Smjnelson	fi
1792cdf0c1d5Smjnelson
1793cdf0c1d5Smjnelson	#
1794cdf0c1d5Smjnelson	# parent's version of the file
1795cdf0c1d5Smjnelson	#
1796cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1797cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1798cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1799cdf0c1d5Smjnelson	#
1800cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1801cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1802cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1803cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1804cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1805cdf0c1d5Smjnelson
1806*02d26c39SVladimir Kotal		if (( $? != 0 )); then
1807cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1808cdf0c1d5Smjnelson		else
1809cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1810cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1811cdf0c1d5Smjnelson			else
1812cdf0c1d5Smjnelson				# should never happen
1813cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1814cdf0c1d5Smjnelson			fi
1815cdf0c1d5Smjnelson		fi
1816cdf0c1d5Smjnelson	fi
1817cdf0c1d5Smjnelson}
1818cdf0c1d5Smjnelson
1819cdf0c1d5Smjnelsonfunction build_old_new_subversion
1820cdf0c1d5Smjnelson{
1821cdf0c1d5Smjnelson	typeset olddir="$1"
1822cdf0c1d5Smjnelson	typeset newdir="$2"
1823cdf0c1d5Smjnelson
1824cdf0c1d5Smjnelson	# Snag new version of file.
1825cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1826cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1827cdf0c1d5Smjnelson
1828cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1829cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1830cdf0c1d5Smjnelson	else
1831cdf0c1d5Smjnelson		# Get the parent's version of the file.
1832cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
1833cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
1834cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
1835cdf0c1d5Smjnelson		fi
1836cdf0c1d5Smjnelson	fi
1837cdf0c1d5Smjnelson}
1838cdf0c1d5Smjnelson
1839cdf0c1d5Smjnelsonfunction build_old_new_unknown
1840cdf0c1d5Smjnelson{
1841cdf0c1d5Smjnelson	typeset olddir="$1"
1842cdf0c1d5Smjnelson	typeset newdir="$2"
1843cdf0c1d5Smjnelson
1844cdf0c1d5Smjnelson	#
1845cdf0c1d5Smjnelson	# Snag new version of file.
1846cdf0c1d5Smjnelson	#
1847cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1848cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1849cdf0c1d5Smjnelson
1850cdf0c1d5Smjnelson	#
1851cdf0c1d5Smjnelson	# Snag the parent's version of the file.
1852cdf0c1d5Smjnelson	#
1853cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
1854cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1855cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1856cdf0c1d5Smjnelson	fi
1857cdf0c1d5Smjnelson}
1858cdf0c1d5Smjnelson
1859cdf0c1d5Smjnelsonfunction build_old_new
1860cdf0c1d5Smjnelson{
1861cdf0c1d5Smjnelson	typeset WDIR=$1
1862cdf0c1d5Smjnelson	typeset PWS=$2
1863cdf0c1d5Smjnelson	typeset PDIR=$3
1864cdf0c1d5Smjnelson	typeset PF=$4
1865cdf0c1d5Smjnelson	typeset CWS=$5
1866cdf0c1d5Smjnelson	typeset DIR=$6
1867cdf0c1d5Smjnelson	typeset F=$7
1868cdf0c1d5Smjnelson
1869cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
1870cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
1871cdf0c1d5Smjnelson
1872cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
1873cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
1874cdf0c1d5Smjnelson
1875cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1876cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
1877cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
1878cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
1879cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
1880cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
1881cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
1882cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
1883cdf0c1d5Smjnelson	fi
1884cdf0c1d5Smjnelson
1885cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
1886cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
1887cdf0c1d5Smjnelson		return 1
1888cdf0c1d5Smjnelson	fi
1889cdf0c1d5Smjnelson	return 0
1890cdf0c1d5Smjnelson}
1891cdf0c1d5Smjnelson
1892cdf0c1d5Smjnelson
1893daaffb31Sdp#
1894daaffb31Sdp# Usage message.
1895daaffb31Sdp#
1896daaffb31Sdpfunction usage
1897daaffb31Sdp{
1898daaffb31Sdp	print 'Usage:\twebrev [common-options]
1899daaffb31Sdp	webrev [common-options] ( <file> | - )
1900daaffb31Sdp	webrev [common-options] -w <wx file>
1901daaffb31Sdp
1902daaffb31SdpOptions:
1903daaffb31Sdp	-O: Print bugids/arc cases suitable for OpenSolaris.
1904daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
1905daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
1906daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
1907*02d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
1908*02d26c39SVladimir Kotal	-U: upload the webrev to remote destination
1909*02d26c39SVladimir Kotal	-n: do not generate the webrev (useful with -U)
1910daaffb31Sdp	-w <wxfile>: Use specified wx active file.
1911daaffb31Sdp
1912daaffb31SdpEnvironment:
1913daaffb31Sdp	WDIR: Control the output directory.
1914daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
1915daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
1916daaffb31Sdp
1917cdf0c1d5SmjnelsonSCM Specific Options:
1918cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
1919cdf0c1d5Smjnelson
1920daaffb31SdpSCM Environment:
1921cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
1922cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
1923daaffb31Sdp'
1924daaffb31Sdp
1925daaffb31Sdp	exit 2
1926daaffb31Sdp}
1927daaffb31Sdp
1928daaffb31Sdp#
1929daaffb31Sdp#
1930daaffb31Sdp# Main program starts here
1931daaffb31Sdp#
1932daaffb31Sdp#
1933daaffb31Sdp
1934daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1935daaffb31Sdp
1936daaffb31Sdpset +o noclobber
1937daaffb31Sdp
1938cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
1939cdf0c1d5Smjnelson
194014983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
194114983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
1942cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
1943cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
194414983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
194514983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
194614983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
1947*02d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
1948cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
1949cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
1950cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
1951cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
1952*02d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
1953*02d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
1954*02d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
1955*02d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
1956cdf0c1d5Smjnelson
195714983201Sdp
195814983201Sdpif [[ ! -x $PERL ]]; then
195914983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
196014983201Sdp	exit 1
1961daaffb31Sdpfi
196214983201Sdp
1963cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
1964cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
1965cdf0c1d5Smjnelson	exit 1
1966cdf0c1d5Smjnelsonfi
1967cdf0c1d5Smjnelson
196814983201Sdp#
196914983201Sdp# These aren't fatal, but we want to note them to the user.
197014983201Sdp# We don't warn on the absence of 'wx' until later when we've
197114983201Sdp# determined that we actually need to try to invoke it.
197214983201Sdp#
197314983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
197414983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
197514983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
1976daaffb31Sdp
1977daaffb31Sdp# Declare global total counters.
1978daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
1979daaffb31Sdp
198014983201Sdpflist_mode=
198114983201Sdpflist_file=
1982daaffb31Sdpiflag=
1983*02d26c39SVladimir Kotallflag=
1984*02d26c39SVladimir KotalNflag=
1985*02d26c39SVladimir Kotalnflag=
1986*02d26c39SVladimir KotalOflag=
1987daaffb31Sdpoflag=
1988daaffb31Sdppflag=
1989*02d26c39SVladimir Kotaltflag=
1990*02d26c39SVladimir Kotaluflag=
1991*02d26c39SVladimir KotalUflag=
1992daaffb31Sdpwflag=
1993*02d26c39SVladimir Kotalremote_target=
1994*02d26c39SVladimir Kotalwhile getopts "i:o:p:lwONnt:U" opt
1995daaffb31Sdpdo
1996daaffb31Sdp	case $opt in
1997daaffb31Sdp	i)	iflag=1
1998daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
1999daaffb31Sdp
2000daaffb31Sdp	#
2001daaffb31Sdp	# If -l has been specified, we need to abort further options
2002daaffb31Sdp	# processing, because subsequent arguments are going to be
2003daaffb31Sdp	# arguments to 'putback -n'.
2004daaffb31Sdp	#
2005daaffb31Sdp	l)	lflag=1
2006daaffb31Sdp		break;;
2007daaffb31Sdp
2008*02d26c39SVladimir Kotal	N)	Nflag=1;;
2009*02d26c39SVladimir Kotal
2010*02d26c39SVladimir Kotal	n)	nflag=1;;
2011daaffb31Sdp
2012daaffb31Sdp	O)	Oflag=1;;
2013daaffb31Sdp
2014*02d26c39SVladimir Kotal	o)	oflag=1
2015*02d26c39SVladimir Kotal		WDIR=$OPTARG;;
2016*02d26c39SVladimir Kotal
2017*02d26c39SVladimir Kotal	p)	pflag=1
2018*02d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
2019*02d26c39SVladimir Kotal
2020*02d26c39SVladimir Kotal	t)	tflag=1
2021*02d26c39SVladimir Kotal		remote_target=$OPTARG;;
2022*02d26c39SVladimir Kotal
2023*02d26c39SVladimir Kotal	U)	Uflag=1;;
2024*02d26c39SVladimir Kotal
2025*02d26c39SVladimir Kotal	w)	wflag=1;;
20263df69ef3SDarren Moffat
2027daaffb31Sdp	?)	usage;;
2028daaffb31Sdp	esac
2029daaffb31Sdpdone
2030daaffb31Sdp
2031daaffb31SdpFLIST=/tmp/$$.flist
2032daaffb31Sdp
2033daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2034daaffb31Sdp	usage
2035daaffb31Sdpfi
2036daaffb31Sdp
2037*02d26c39SVladimir Kotal# more sanity checking
2038*02d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2039*02d26c39SVladimir Kotal	print "it does not make sense to skip webrev generation without -U"
2040*02d26c39SVladimir Kotal	exit 1
2041*02d26c39SVladimir Kotalfi
2042*02d26c39SVladimir Kotal
2043*02d26c39SVladimir Kotalif [[ -n $tflag && -z $Uflag ]]; then
2044*02d26c39SVladimir Kotal	echo "remote target has to be used only for upload"
2045*02d26c39SVladimir Kotal	exit 1
2046*02d26c39SVladimir Kotalfi
2047*02d26c39SVladimir Kotal
2048daaffb31Sdp#
2049daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2050daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2051daaffb31Sdp#
2052daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2053daaffb31Sdp	parent_webrev="$codemgr_parent"
2054daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2055daaffb31Sdpfi
2056daaffb31Sdp
2057daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2058daaffb31Sdp	shift $(($OPTIND - 1))
2059daaffb31Sdp
2060daaffb31Sdp	if [[ $1 == "-" ]]; then
2061daaffb31Sdp		cat > $FLIST
206214983201Sdp		flist_mode="stdin"
206314983201Sdp		flist_done=1
206414983201Sdp		shift
2065daaffb31Sdp	elif [[ -n $1 ]]; then
206614983201Sdp		if [[ ! -r $1 ]]; then
2067daaffb31Sdp			print -u2 "$1: no such file or not readable"
2068daaffb31Sdp			usage
2069daaffb31Sdp		fi
2070daaffb31Sdp		cat $1 > $FLIST
207114983201Sdp		flist_mode="file"
207214983201Sdp		flist_file=$1
207314983201Sdp		flist_done=1
207414983201Sdp		shift
2075daaffb31Sdp	else
207614983201Sdp		flist_mode="auto"
2077daaffb31Sdp	fi
2078daaffb31Sdpfi
2079daaffb31Sdp
2080daaffb31Sdp#
2081daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2082daaffb31Sdp# is in use.
2083daaffb31Sdp#
2084cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
2085cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2086cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2087cdf0c1d5Smjnelson	;;
2088cdf0c1d5Smjnelsonunknown)
2089cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2090cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2091cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
20927c478bd9Sstevel@tonic-gate		exit 1
20937c478bd9Sstevel@tonic-gate	fi
2094cdf0c1d5Smjnelson	;;
2095cdf0c1d5Smjnelson*)
2096cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2097cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2098cdf0c1d5Smjnelson		exit 1
2099cdf0c1d5Smjnelson	fi
2100cdf0c1d5Smjnelson	;;
2101cdf0c1d5Smjnelsonesac
21027c478bd9Sstevel@tonic-gate
2103daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2104daaffb31Sdp
2105daaffb31Sdpif [[ -n $lflag ]]; then
2106daaffb31Sdp	#
2107daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2108daaffb31Sdp	# then generate the file list by extracting file names from a
2109daaffb31Sdp	# putback -n.
2110daaffb31Sdp	#
2111daaffb31Sdp	shift $(($OPTIND - 1))
2112cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2113daaffb31Sdp		flist_from_teamware "$*"
2114cdf0c1d5Smjnelson	else
2115cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2116cdf0c1d5Smjnelson		exit 1
2117cdf0c1d5Smjnelson	fi
2118daaffb31Sdp	flist_done=1
2119daaffb31Sdp	shift $#
2120daaffb31Sdpelif [[ -n $wflag ]]; then
2121daaffb31Sdp	#
2122daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2123daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2124daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2125daaffb31Sdp	# in building the index.html file.
2126daaffb31Sdp	#
2127daaffb31Sdp	shift $(($OPTIND - 1))
2128daaffb31Sdp	wxfile=$1
2129daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2130daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2131daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2132daaffb31Sdp		fi
2133daaffb31Sdp	fi
2134daaffb31Sdp
2135daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2136daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2137daaffb31Sdp
2138cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2139cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2140cdf0c1d5Smjnelson		usage
2141cdf0c1d5Smjnelson	fi
2142cdf0c1d5Smjnelson
2143daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2144daaffb31Sdp	flist_from_wx $wxfile
2145daaffb31Sdp	flist_done=1
2146daaffb31Sdp	if [[ -n "$*" ]]; then
2147daaffb31Sdp		shift
2148daaffb31Sdp	fi
214914983201Sdpelif [[ $flist_mode == "stdin" ]]; then
215014983201Sdp	print -u2 " File list from: standard input"
215114983201Sdpelif [[ $flist_mode == "file" ]]; then
215214983201Sdp	print -u2 " File list from: $flist_file"
2153daaffb31Sdpfi
2154daaffb31Sdp
2155daaffb31Sdpif [[ $# -gt 0 ]]; then
215614983201Sdp	print -u2 "WARNING: unused arguments: $*"
2157daaffb31Sdpfi
2158daaffb31Sdp
2159daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
2160daaffb31Sdp	#
2161daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
2162daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
2163daaffb31Sdp	#
2164daaffb31Sdp	#      1) on the command line (only for the parent)
2165daaffb31Sdp	#      2) in the user environment
2166daaffb31Sdp	#      3) in the flist
2167daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
2168daaffb31Sdp	#
2169daaffb31Sdp
2170daaffb31Sdp	#
2171daaffb31Sdp	# Here is case (2): the user environment
2172daaffb31Sdp	#
2173daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2174daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2175daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
21767c478bd9Sstevel@tonic-gate		exit 1
21777c478bd9Sstevel@tonic-gate	fi
21787c478bd9Sstevel@tonic-gate
2179daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2180daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2181daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2182daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
21837c478bd9Sstevel@tonic-gate		exit 1
21847c478bd9Sstevel@tonic-gate	fi
21857c478bd9Sstevel@tonic-gate
2186daaffb31Sdp	#
2187daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2188daaffb31Sdp	# list, then see if we can get it by probing for wx.
2189daaffb31Sdp	#
219014983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
219114983201Sdp		if [[ ! -x $WX ]]; then
219214983201Sdp			print -u2 "WARNING: wx not found!"
2193daaffb31Sdp		fi
21947c478bd9Sstevel@tonic-gate
2195daaffb31Sdp		#
2196daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2197daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2198daaffb31Sdp		# hang asking us to initialize our wx information.
2199daaffb31Sdp		#
220014983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2201daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2202daaffb31Sdp			$WX list -w > $FLIST
2203daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2204daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2205daaffb31Sdp			print -u2 "done"
2206daaffb31Sdp			flist_done=1
2207daaffb31Sdp		fi
2208daaffb31Sdp	fi
2209daaffb31Sdp
2210daaffb31Sdp	#
2211daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2212daaffb31Sdp	# from the command line), eval it to extract environment variables from
2213daaffb31Sdp	# it: This is step (3).
2214daaffb31Sdp	#
2215daaffb31Sdp	env_from_flist
2216daaffb31Sdp
2217daaffb31Sdp	#
2218daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2219daaffb31Sdp	# it from teamware.
2220daaffb31Sdp	#
2221daaffb31Sdp	if [[ -z $flist_done ]]; then
2222daaffb31Sdp		flist_from_teamware
2223daaffb31Sdp		env_from_flist
2224daaffb31Sdp	fi
2225daaffb31Sdp
2226daaffb31Sdp	#
2227daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2228daaffb31Sdp	# from workspace.
2229daaffb31Sdp	#
2230cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2231daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2232daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2233daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2234daaffb31Sdp		exit 1
2235daaffb31Sdp	fi
2236daaffb31Sdp
2237daaffb31Sdp	#
2238cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2239cdf0c1d5Smjnelson	# webrev title.
2240cdf0c1d5Smjnelson	#
2241cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2242cdf0c1d5Smjnelson
2243cdf0c1d5Smjnelson	#
2244daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2245daaffb31Sdp	#
2246daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2247daaffb31Sdp	CWS=$codemgr_ws
2248daaffb31Sdp	PWS=$codemgr_parent
2249cdf0c1d5Smjnelson
2250cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2251cdf0c1d5Smjnelson
2252cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2253cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2254cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2255cdf0c1d5Smjnelson
2256cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2257cdf0c1d5Smjnelson
2258cdf0c1d5Smjnelson	#
2259cdf0c1d5Smjnelson	# Parent can either be specified with -p
2260cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2261cdf0c1d5Smjnelson	# or taken from hg's default path.
2262cdf0c1d5Smjnelson	#
2263cdf0c1d5Smjnelson
2264cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2265cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2266cdf0c1d5Smjnelson	fi
2267cdf0c1d5Smjnelson
2268cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2269cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2270cdf0c1d5Smjnelson	fi
2271cdf0c1d5Smjnelson
2272cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2273cdf0c1d5Smjnelson	CWS=$codemgr_ws
2274cdf0c1d5Smjnelson	PWS=$codemgr_parent
2275cdf0c1d5Smjnelson
2276cdf0c1d5Smjnelson	#
2277cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2278cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2279cdf0c1d5Smjnelson	#
2280cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2281cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2282cdf0c1d5Smjnelson	else
2283cdf0c1d5Smjnelson		real_parent=$PWS
2284cdf0c1d5Smjnelson	fi
2285cdf0c1d5Smjnelson
2286cdf0c1d5Smjnelson	#
2287cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2288cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2289cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2290cdf0c1d5Smjnelson	# files mentioned in the flist.
2291cdf0c1d5Smjnelson	#
2292cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2293cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2294cdf0c1d5Smjnelson		flist_done=1
2295cdf0c1d5Smjnelson	fi
2296cdf0c1d5Smjnelson
2297cdf0c1d5Smjnelson	#
2298cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2299cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2300cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2301cdf0c1d5Smjnelson	# in the user-specified flist.
2302cdf0c1d5Smjnelson	#
2303cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2304cdf0c1d5Smjnelson		env_from_flist
2305cdf0c1d5Smjnelson	fi
2306cdf0c1d5Smjnelson
2307cdf0c1d5Smjnelson	#
2308cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2309cdf0c1d5Smjnelson	#
2310cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2311cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2312cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2313cdf0c1d5Smjnelson		print " Done."
2314cdf0c1d5Smjnelson	fi
2315cdf0c1d5Smjnelson
2316cdf0c1d5Smjnelson	#
2317cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2318cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2319cdf0c1d5Smjnelson	# if we don't have one.
2320cdf0c1d5Smjnelson	#
2321cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2322*02d26c39SVladimir Kotal		eval `sed -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2323cdf0c1d5Smjnelson	fi
2324cdf0c1d5Smjnelson
2325cdf0c1d5Smjnelson	#
2326cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2327cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2328cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2329cdf0c1d5Smjnelson	#
2330cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2331cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2332*02d26c39SVladimir Kotal		    eval `sed -e "s/#.*$//" | $GREP HG_PARENT=`
2333cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2334cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2335cdf0c1d5Smjnelson		exit 1
2336cdf0c1d5Smjnelson	fi
2337cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2338cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2339cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2340cdf0c1d5Smjnelson	else
2341cdf0c1d5Smjnelson		svn info | while read line; do
2342cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2343cdf0c1d5Smjnelson				url=${line#URL: }
2344cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2345cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2346cdf0c1d5Smjnelson			fi
2347cdf0c1d5Smjnelson		done
2348cdf0c1d5Smjnelson
2349cdf0c1d5Smjnelson		rel=${url#$repo}
2350cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2351cdf0c1d5Smjnelson	fi
2352cdf0c1d5Smjnelson
2353cdf0c1d5Smjnelson	#
2354cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2355cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2356cdf0c1d5Smjnelson	#
2357cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2358cdf0c1d5Smjnelson
2359cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2360cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2361cdf0c1d5Smjnelson	fi
2362cdf0c1d5Smjnelsonelse
2363cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2364cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2365cdf0c1d5Smjnelson    else
2366cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2367cdf0c1d5Smjnelson    fi
2368cdf0c1d5Smjnelson
2369cdf0c1d5Smjnelson    env_from_flist
2370cdf0c1d5Smjnelson
2371cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2372cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2373cdf0c1d5Smjnelson	exit 1
2374cdf0c1d5Smjnelson    fi
2375cdf0c1d5Smjnelson
2376cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2377cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2378cdf0c1d5Smjnelson	exit 1
2379cdf0c1d5Smjnelson    fi
2380cdf0c1d5Smjnelson
2381cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2382cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2383daaffb31Sdpfi
2384daaffb31Sdp
2385daaffb31Sdp#
2386daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2387daaffb31Sdp# webrev-info file in the workspace directory.
2388daaffb31Sdp#
2389daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2390daaffb31Sdp	iflag=1
2391daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2392daaffb31Sdpfi
2393daaffb31Sdp
2394daaffb31Sdpif [[ -n $iflag ]]; then
2395daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2396daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2397daaffb31Sdp		    "not readable."
2398daaffb31Sdp		exit 1
2399daaffb31Sdp	else
2400daaffb31Sdp		#
2401daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2402daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2403daaffb31Sdp		#
2404daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2405daaffb31Sdp	fi
2406daaffb31Sdpfi
2407daaffb31Sdp
2408daaffb31Sdp#
2409daaffb31Sdp# Output directory.
2410daaffb31Sdp#
2411daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2412daaffb31Sdp
2413daaffb31Sdp#
2414*02d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
2415*02d26c39SVladimir Kotal# in the future this could potentially be an option.
2416daaffb31Sdp#
2417*02d26c39SVladimir Kotalif [[ -n $oflag ]]; then
2418*02d26c39SVladimir Kotal	WNAME=${WDIR##*/}
2419*02d26c39SVladimir Kotalelse
2420daaffb31Sdp	WNAME=${CWS##*/}
2421*02d26c39SVladimir Kotalfi
2422*02d26c39SVladimir Kotal
2423*02d26c39SVladimir Kotal# Do not generate the webrev, just upload it. We trust the user that the
2424*02d26c39SVladimir Kotal# webrev is OpenSolaris one.
2425*02d26c39SVladimir Kotalif [[ -n $Uflag && -n $nflag ]]; then
2426*02d26c39SVladimir Kotal	upload_webrev
2427*02d26c39SVladimir Kotal	exit $?
2428*02d26c39SVladimir Kotalfi
2429daaffb31Sdp
2430e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
24317c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
24327c478bd9Sstevel@tonic-gatefi
2433daaffb31Sdp
2434daaffb31Sdpif [[ ! -d $WDIR ]]; then
2435daaffb31Sdp	mkdir -p $WDIR
2436daaffb31Sdp	[[ $? != 0 ]] && exit 1
24377c478bd9Sstevel@tonic-gatefi
24387c478bd9Sstevel@tonic-gate
2439daaffb31Sdp#
2440daaffb31Sdp# Summarize what we're going to do.
2441daaffb31Sdp#
2442cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2443cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2444cdf0c1d5Smjnelsonelse
2445daaffb31Sdp	print "      Workspace: $CWS"
2446cdf0c1d5Smjnelsonfi
2447daaffb31Sdpif [[ -n $parent_webrev ]]; then
2448daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2449daaffb31Sdpelse
2450cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2451cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2452cdf0c1d5Smjnelson			| sed -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2453cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2454cdf0c1d5Smjnelson	else
2455daaffb31Sdp		print "Compare against: $PWS"
2456daaffb31Sdp	fi
2457cdf0c1d5Smjnelsonfi
2458daaffb31Sdp
2459daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2460daaffb31Sdpprint "      Output to: $WDIR"
2461daaffb31Sdp
2462daaffb31Sdp#
24637c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2464daaffb31Sdp#
2465daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
24667c478bd9Sstevel@tonic-gate
2467daaffb31Sdp#
2468daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2469daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2470daaffb31Sdp#
2471daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2472daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2473daaffb31Sdp[[ -n "$Oflag" ]] && \
2474daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
24757c478bd9Sstevel@tonic-gate
2476daaffb31Sdp#
2477daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2478daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2479daaffb31Sdp#
2480daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2481daaffb31Sdp#    SACURL.  See sac2url().
2482daaffb31Sdp#
2483daaffb31SdpSACURL='http://sac.eng.sun.com'
2484daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2485e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2486daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
24877c478bd9Sstevel@tonic-gate
2488daaffb31Sdprm -f $WDIR/$WNAME.patch
2489daaffb31Sdprm -f $WDIR/$WNAME.ps
2490daaffb31Sdprm -f $WDIR/$WNAME.pdf
24917c478bd9Sstevel@tonic-gate
2492daaffb31Sdptouch $WDIR/$WNAME.patch
24937c478bd9Sstevel@tonic-gate
2494daaffb31Sdpprint "   Output Files:"
2495daaffb31Sdp
2496daaffb31Sdp#
2497daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2498daaffb31Sdp#
2499daaffb31Sdpsed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2500daaffb31SdpFLIST=/tmp/$$.flist.clean
2501daaffb31Sdp
2502daaffb31Sdp#
2503cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2504cdf0c1d5Smjnelson#
2505cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2506cdf0c1d5Smjnelson	#
2507cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2508cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2509cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2510cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2511cdf0c1d5Smjnelson	#    keep only the old name.
2512cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2513cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2514cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2515cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2516cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2517cdf0c1d5Smjnelson	#
2518cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2519cdf0c1d5Smjnelson	sed '
2520cdf0c1d5Smjnelson		s#^[^ ]* ##
2521cdf0c1d5Smjnelson		s#/#\\\/#g
2522cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2523cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2524cdf0c1d5Smjnelson
2525cdf0c1d5Smjnelson	#
2526cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2527cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2528cdf0c1d5Smjnelson	#
2529cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2530cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2531cdf0c1d5Smjnelson	    sed -n -f $SEDFILE > $HG_PARENT_MANIFEST
2532cdf0c1d5Smjnelsonfi
2533cdf0c1d5Smjnelson
2534cdf0c1d5Smjnelson#
2535daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2536daaffb31Sdp#
2537daaffb31Sdpcat $FLIST | while read LINE
25387c478bd9Sstevel@tonic-gatedo
25397c478bd9Sstevel@tonic-gate	set - $LINE
25407c478bd9Sstevel@tonic-gate	P=$1
25417c478bd9Sstevel@tonic-gate
2542daaffb31Sdp	#
2543daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2544daaffb31Sdp	# file that has been modified or created in the child.  A file
2545daaffb31Sdp	# that is renamed in the child workspace has two names on the
2546daaffb31Sdp	# line: new name followed by the old name.
2547daaffb31Sdp	#
2548daaffb31Sdp	oldname=""
2549daaffb31Sdp	oldpath=""
2550daaffb31Sdp	rename=
2551daaffb31Sdp	if [[ $# -eq 2 ]]; then
25527c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2553daaffb31Sdp		oldname=" (was $PP)"
2554daaffb31Sdp		oldpath="$PP"
2555daaffb31Sdp		rename=1
25567c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2557daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
25587c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
25597c478bd9Sstevel@tonic-gate		fi
25607c478bd9Sstevel@tonic-gate
25617c478bd9Sstevel@tonic-gate		PF=${PP##*/}
25627c478bd9Sstevel@tonic-gate
25637c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2564daaffb31Sdp	        if [[ $DIR == $P ]]; then
25657c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
25667c478bd9Sstevel@tonic-gate		fi
25677c478bd9Sstevel@tonic-gate
25687c478bd9Sstevel@tonic-gate		F=${P##*/}
2569daaffb31Sdp
25707c478bd9Sstevel@tonic-gate        else
25717c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2572daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
25737c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
25747c478bd9Sstevel@tonic-gate		fi
25757c478bd9Sstevel@tonic-gate
25767c478bd9Sstevel@tonic-gate		F=${P##*/}
25777c478bd9Sstevel@tonic-gate
25787c478bd9Sstevel@tonic-gate		PP=$P
25797c478bd9Sstevel@tonic-gate		PDIR=$DIR
25807c478bd9Sstevel@tonic-gate		PF=$F
25817c478bd9Sstevel@tonic-gate	fi
25827c478bd9Sstevel@tonic-gate
2583daaffb31Sdp	COMM=`getcomments html $P $PP`
25847c478bd9Sstevel@tonic-gate
2585daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
25867c478bd9Sstevel@tonic-gate
25877c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
25887c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
25897c478bd9Sstevel@tonic-gate
2590daaffb31Sdp	#
2591daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2592daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2593e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2594daaffb31Sdp	#
2595e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2596daaffb31Sdp		pclosed=${P##usr/closed/}
2597e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2598e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2599daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2600daaffb31Sdp			    "mode review"
2601daaffb31Sdp			continue
2602daaffb31Sdp		fi
2603daaffb31Sdp	fi
2604daaffb31Sdp
2605daaffb31Sdp	#
2606cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2607daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2608daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2609daaffb31Sdp	#
2610daaffb31Sdp
2611cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
26127c478bd9Sstevel@tonic-gate	    continue
26137c478bd9Sstevel@tonic-gate
2614cdf0c1d5Smjnelson	#
2615cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2616cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2617cdf0c1d5Smjnelson	# consistent environment.
2618cdf0c1d5Smjnelson	#
2619cdf0c1d5Smjnelson	OWD=$PWD
2620daaffb31Sdp	cd $WDIR/raw_files
2621daaffb31Sdp	ofile=old/$PDIR/$PF
2622daaffb31Sdp	nfile=new/$DIR/$F
26237c478bd9Sstevel@tonic-gate
2624daaffb31Sdp	mv_but_nodiff=
2625daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2626daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2627daaffb31Sdp		mv_but_nodiff=1
2628daaffb31Sdp	fi
2629daaffb31Sdp
2630daaffb31Sdp	#
2631daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2632daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2633daaffb31Sdp	#
2634daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2635daaffb31Sdp	#	  diff and an 'add' diff
2636daaffb31Sdp	#	- new files and deleted files must be handled specially
2637daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2638daaffb31Sdp	#	  (and hence renames) as of this writing.
2639daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2640daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2641daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2642daaffb31Sdp	#         transformations:
2643daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2644daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2645daaffb31Sdp	#
2646daaffb31Sdp	cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2647daaffb31Sdp	cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2648daaffb31Sdp
2649daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2650daaffb31Sdp	if [[ -z $rename ]]; then
2651e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2652daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2653daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2654e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2655daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2656daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2657daaffb31Sdp		else
2658daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2659daaffb31Sdp		fi
2660daaffb31Sdp	else
2661daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2662daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2663daaffb31Sdp
2664daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2665daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2666daaffb31Sdp
2667daaffb31Sdp	fi
2668daaffb31Sdp
2669daaffb31Sdp	#
2670daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2671daaffb31Sdp	# whole wad.
2672daaffb31Sdp	#
2673daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2674daaffb31Sdp
2675daaffb31Sdp	print " patch\c"
2676daaffb31Sdp
2677daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2678daaffb31Sdp
2679daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2680daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2681daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
26827c478bd9Sstevel@tonic-gate		print " cdiffs\c"
26837c478bd9Sstevel@tonic-gate
2684daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2685daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2686daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2687daaffb31Sdp
26887c478bd9Sstevel@tonic-gate		print " udiffs\c"
26897c478bd9Sstevel@tonic-gate
26907c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2691daaffb31Sdp			$WDIFF -c "$COMM" \
2692daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2693daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2694daaffb31Sdp			if [[ $? -eq 0 ]]; then
26957c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2696daaffb31Sdp			else
2697daaffb31Sdp				print " wdiffs[fail]\c"
2698daaffb31Sdp			fi
26997c478bd9Sstevel@tonic-gate		fi
27007c478bd9Sstevel@tonic-gate
2701daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2702daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
27037c478bd9Sstevel@tonic-gate		print " sdiffs\c"
27047c478bd9Sstevel@tonic-gate
27057c478bd9Sstevel@tonic-gate		print " frames\c"
27067c478bd9Sstevel@tonic-gate
27077c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
27087c478bd9Sstevel@tonic-gate
2709daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2710daaffb31Sdp
2711daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2712daaffb31Sdp		# renamed file: may also have differences
2713daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2714daaffb31Sdp	elif [[ -f $nfile ]]; then
27157c478bd9Sstevel@tonic-gate		# new file: count added lines
2716daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2717daaffb31Sdp	elif [[ -f $ofile ]]; then
27187c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2719daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
27207c478bd9Sstevel@tonic-gate	fi
27217c478bd9Sstevel@tonic-gate
2722daaffb31Sdp	#
2723daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
2724daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
2725daaffb31Sdp	# tree-killing to print out the contents of deleted files).
2726daaffb31Sdp	#
2727daaffb31Sdp	if [[ -f $nfile ]]; then
2728daaffb31Sdp		ocr=$ofile
2729daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
2730daaffb31Sdp
2731daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
2732daaffb31Sdp			textcomm=`getcomments text $P $PP`
273314983201Sdp			if [[ -x $CODEREVIEW ]]; then
273414983201Sdp				$CODEREVIEW -y "$textcomm" \
273514983201Sdp				    -e $ocr $nfile \
273614983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
273714983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
2738daaffb31Sdp				if [[ $? -eq 0 ]]; then
2739daaffb31Sdp					print " ps\c"
2740daaffb31Sdp				else
2741daaffb31Sdp					print " ps[fail]\c"
2742daaffb31Sdp				fi
2743daaffb31Sdp			fi
2744daaffb31Sdp		fi
274514983201Sdp	fi
2746daaffb31Sdp
2747cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
2748cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
27497c478bd9Sstevel@tonic-gate		print " old\c"
27507c478bd9Sstevel@tonic-gate	fi
27517c478bd9Sstevel@tonic-gate
2752daaffb31Sdp	if [[ -f $nfile ]]; then
2753daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
27547c478bd9Sstevel@tonic-gate		print " new\c"
27557c478bd9Sstevel@tonic-gate	fi
27567c478bd9Sstevel@tonic-gate
2757cdf0c1d5Smjnelson	cd $OWD
2758cdf0c1d5Smjnelson
2759daaffb31Sdp	print
27607c478bd9Sstevel@tonic-gatedone
27617c478bd9Sstevel@tonic-gate
2762daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
27637c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
2764daaffb31Sdp
276514983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
276614983201Sdp	print " Generating PDF: Skipped: no output available"
276714983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
276814983201Sdp	print " Generating PDF: \c"
276914983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
2770daaffb31Sdp	print "Done."
277114983201Sdpelse
277214983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
277314983201Sdpfi
27747c478bd9Sstevel@tonic-gate
2775e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
2776e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
2777e0e0293aSjmcp
2778e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
2779e0e0293aSjmcp	/usr/bin/find $WDIR -type d -name closed -exec /bin/rm -rf {} \;
2780e0e0293aSjmcpfi
2781e0e0293aSjmcp
27827c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
27837c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
27847c478bd9Sstevel@tonic-gate
27857c478bd9Sstevel@tonic-gatecd $CWS
27867c478bd9Sstevel@tonic-gate
27877c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
2788daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
27897c478bd9Sstevel@tonic-gate
2790daaffb31Sdpprint "     index.html: \c"
27917c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
27927c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
27937c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
27947c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
27957c478bd9Sstevel@tonic-gate
2796daaffb31Sdpprint "$HTML<head>$STDHEAD"
2797daaffb31Sdpprint "<title>$WNAME</title>"
2798daaffb31Sdpprint "</head>"
2799daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
2800daaffb31Sdpprint "<div class=\"summary\">"
2801daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
28027c478bd9Sstevel@tonic-gate
2803daaffb31Sdpprint "<table>"
28047c478bd9Sstevel@tonic-gate
2805daaffb31Sdp#
2806cdf0c1d5Smjnelson# Get the preparer's name:
2807daaffb31Sdp#
2808cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
2809cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
2810cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
2811cdf0c1d5Smjnelson#
2812cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
2813cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
2814cdf0c1d5Smjnelson#
2815cdf0c1d5Smjnelsonpreparer=
2816cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
2817cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
2818cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
2819cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
2820cdf0c1d5Smjnelson	fi
2821cdf0c1d5Smjnelsonfi
2822cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
2823cdf0c1d5Smjnelson	preparer=$(
2824cdf0c1d5Smjnelson	    $PERL -e '
2825cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
2826cdf0c1d5Smjnelson	        if ($login) {
2827cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
2828cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
2829cdf0c1d5Smjnelson	        } else {
2830cdf0c1d5Smjnelson	            printf "(unknown)\n";
2831cdf0c1d5Smjnelson	        }
2832cdf0c1d5Smjnelson	')
2833daaffb31Sdpfi
2834daaffb31Sdp
2835cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
2836cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
2837cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2838cdf0c1d5Smjnelson	print "(at $CWS_REV)"
2839cdf0c1d5Smjnelsonfi
2840cdf0c1d5Smjnelsonprint "</td></tr>"
2841daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
2842daaffb31Sdpif [[ -n $parent_webrev ]]; then
2843daaffb31Sdp	print "webrev at $parent_webrev"
2844daaffb31Sdpelse
2845daaffb31Sdp	print "$PWS"
2846cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
2847cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
2848cdf0c1d5Smjnelson	fi
2849daaffb31Sdpfi
2850daaffb31Sdpprint "</td></tr>"
2851daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
2852daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
2853daaffb31Sdpprint "</td></tr>"
2854daaffb31Sdp
2855daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
2856daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
2857daaffb31Sdp	print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
2858daaffb31Sdpfi
2859daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
2860daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
2861daaffb31Sdp	print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
2862daaffb31Sdpfi
2863daaffb31Sdp
2864daaffb31Sdpif [[ -n "$iflag" ]]; then
2865daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
2866daaffb31Sdp	cat /tmp/$$.include
2867daaffb31Sdp	print "</div></td></tr>"
2868daaffb31Sdpfi
2869daaffb31Sdpprint "</table>"
2870daaffb31Sdpprint "</div>"
2871daaffb31Sdp
2872daaffb31Sdp#
2873daaffb31Sdp# Second pass through the files: generate the rest of the index file
2874daaffb31Sdp#
2875daaffb31Sdpcat $FLIST | while read LINE
28767c478bd9Sstevel@tonic-gatedo
28777c478bd9Sstevel@tonic-gate	set - $LINE
28787c478bd9Sstevel@tonic-gate	P=$1
28797c478bd9Sstevel@tonic-gate
2880daaffb31Sdp	if [[ $# == 2 ]]; then
28817c478bd9Sstevel@tonic-gate		PP=$2
2882cdf0c1d5Smjnelson		oldname="$PP"
28837c478bd9Sstevel@tonic-gate	else
28847c478bd9Sstevel@tonic-gate		PP=$P
2885daaffb31Sdp		oldname=""
2886daaffb31Sdp	fi
2887daaffb31Sdp
2888cdf0c1d5Smjnelson	mv_but_nodiff=
2889cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
2890cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
2891cdf0c1d5Smjnelson		mv_but_nodiff=1
2892cdf0c1d5Smjnelson	fi
2893cdf0c1d5Smjnelson
2894daaffb31Sdp	DIR=${P%/*}
2895daaffb31Sdp	if [[ $DIR == $P ]]; then
2896daaffb31Sdp		DIR="."   # File at root of workspace
28977c478bd9Sstevel@tonic-gate	fi
28987c478bd9Sstevel@tonic-gate
28997c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
29007c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
29017c478bd9Sstevel@tonic-gate	# appear twice in the file list
29027c478bd9Sstevel@tonic-gate
29037c478bd9Sstevel@tonic-gate	F=$WDIR/$P
29047c478bd9Sstevel@tonic-gate
2905daaffb31Sdp	print "<p>"
29067c478bd9Sstevel@tonic-gate
29077c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
29087c478bd9Sstevel@tonic-gate
2909daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
2910daaffb31Sdp		print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
2911daaffb31Sdp		print "<a href=\"$P.udiff.html\">Udiffs</a>"
29127c478bd9Sstevel@tonic-gate
2913daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
2914daaffb31Sdp			print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
29157c478bd9Sstevel@tonic-gate		fi
29167c478bd9Sstevel@tonic-gate
2917daaffb31Sdp		print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
29187c478bd9Sstevel@tonic-gate
29197c478bd9Sstevel@tonic-gate		print "<a href=\"$P.frames.html\">Frames</a>"
29207c478bd9Sstevel@tonic-gate	else
2921daaffb31Sdp		print " ------ ------ ------"
29227c478bd9Sstevel@tonic-gate
2923daaffb31Sdp		if [[ -x $WDIFF ]]; then
29247c478bd9Sstevel@tonic-gate			print " ------"
29257c478bd9Sstevel@tonic-gate		fi
2926daaffb31Sdp
2927daaffb31Sdp		print " ------"
29287c478bd9Sstevel@tonic-gate	fi
29297c478bd9Sstevel@tonic-gate
29307c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
29317c478bd9Sstevel@tonic-gate
2932daaffb31Sdp	if [[ -f $F-.html ]]; then
2933daaffb31Sdp		print "<a href=\"$P-.html\">Old</a>"
29347c478bd9Sstevel@tonic-gate	else
2935daaffb31Sdp		print " ---"
29367c478bd9Sstevel@tonic-gate	fi
29377c478bd9Sstevel@tonic-gate
29387c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
29397c478bd9Sstevel@tonic-gate
2940daaffb31Sdp	if [[ -f $F.html ]]; then
2941daaffb31Sdp		print "<a href=\"$P.html\">New</a>"
29427c478bd9Sstevel@tonic-gate	else
2943daaffb31Sdp		print " ---"
29447c478bd9Sstevel@tonic-gate	fi
29457c478bd9Sstevel@tonic-gate
2946daaffb31Sdp	if [[ -f $F.patch ]]; then
2947daaffb31Sdp		print "<a href=\"$P.patch\">Patch</a>"
2948daaffb31Sdp	else
2949daaffb31Sdp		print " -----"
2950daaffb31Sdp	fi
2951daaffb31Sdp
2952daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
2953daaffb31Sdp		print "<a href=\"raw_files/new/$P\">Raw</a>"
2954daaffb31Sdp	else
2955daaffb31Sdp		print " ---"
2956daaffb31Sdp	fi
2957daaffb31Sdp
2958cdf0c1d5Smjnelson	print "<b>$P</b>"
2959cdf0c1d5Smjnelson
2960cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
2961cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
2962cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
2963cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
2964cdf0c1d5Smjnelson		else
2965cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
2966cdf0c1d5Smjnelson		fi
2967cdf0c1d5Smjnelson	fi
2968cdf0c1d5Smjnelson
2969cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
2970cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
2971cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
2972cdf0c1d5Smjnelson	fi
2973daaffb31Sdp
2974daaffb31Sdp	#
2975e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
2976daaffb31Sdp	#
2977daaffb31Sdp	if [ ! -z "$Oflag" ]; then
2978e0e0293aSjmcp		if [[ $P == usr/closed/* || \
2979e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
2980daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
2981daaffb31Sdp			    "this review</i>"
2982daaffb31Sdp		fi
2983daaffb31Sdp	fi
2984daaffb31Sdp
2985daaffb31Sdp	print "</p>"
29867c478bd9Sstevel@tonic-gate	# Insert delta comments
29877c478bd9Sstevel@tonic-gate
2988daaffb31Sdp	print "<blockquote><pre>"
2989daaffb31Sdp	getcomments html $P $PP
2990daaffb31Sdp	print "</pre>"
29917c478bd9Sstevel@tonic-gate
29927c478bd9Sstevel@tonic-gate	# Add additional comments comment
29937c478bd9Sstevel@tonic-gate
2994daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
29957c478bd9Sstevel@tonic-gate
29967c478bd9Sstevel@tonic-gate	# Add count of changes.
29977c478bd9Sstevel@tonic-gate
2998daaffb31Sdp	if [[ -f $F.count ]]; then
29997c478bd9Sstevel@tonic-gate	    cat $F.count
30007c478bd9Sstevel@tonic-gate	    rm $F.count
30017c478bd9Sstevel@tonic-gate	fi
3002cdf0c1d5Smjnelson
3003cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3004cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3005cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3006cdf0c1d5Smjnelson
3007cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3008cdf0c1d5Smjnelson		# 1) New executable files
3009cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3010cdf0c1d5Smjnelson		# 3) Existing executable files
3011cdf0c1d5Smjnelson
3012cdf0c1d5Smjnelson		old_mode=
3013cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3014cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3015cdf0c1d5Smjnelson		fi
3016cdf0c1d5Smjnelson
3017cdf0c1d5Smjnelson		new_mode=
3018cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3019cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3020cdf0c1d5Smjnelson		fi
3021cdf0c1d5Smjnelson
3022cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3023cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3024cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3025cdf0c1d5Smjnelson			print "</span>"
3026cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3027cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3028cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3029cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3030cdf0c1d5Smjnelson			print "</span>"
3031cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3032cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3033cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3034cdf0c1d5Smjnelson			print "</span>"
3035cdf0c1d5Smjnelson		fi
3036cdf0c1d5Smjnelson	fi
3037cdf0c1d5Smjnelson
3038daaffb31Sdp	print "</blockquote>"
30397c478bd9Sstevel@tonic-gatedone
30407c478bd9Sstevel@tonic-gate
3041daaffb31Sdpprint
3042daaffb31Sdpprint
3043cac38512Smjnelsonprint "<hr></hr>"
3044daaffb31Sdpprint "<p style=\"font-size: small\">"
30459a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3046daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3047daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3048e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3049daaffb31Sdpprint "</body>"
3050daaffb31Sdpprint "</html>"
30517c478bd9Sstevel@tonic-gate
30527c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
30537c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
30547c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
30557c478bd9Sstevel@tonic-gate
3056daaffb31Sdpprint "Done."
3057*02d26c39SVladimir Kotal
3058*02d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
3059*02d26c39SVladimir Kotal	upload_webrev
3060*02d26c39SVladimir Kotal	exit $?
3061*02d26c39SVladimir Kotalfi
3062