xref: /titanic_53/usr/src/tools/scripts/webrev.sh (revision ba44d8a2c0715f679ac0ccf227c557994cdb94a7)
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
14402d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
145*ba44d8a2SVladimir Kotalfunction rsync_upload
14602d26c39SVladimir Kotal{
14702d26c39SVladimir Kotal	if (( $# != 1 )); then
14802d26c39SVladimir Kotal		return 1
14902d26c39SVladimir Kotal	fi
15002d26c39SVladimir Kotal
15102d26c39SVladimir Kotal	typeset dst=$1
15202d26c39SVladimir Kotal
153*ba44d8a2SVladimir Kotal	print "        Syncing: \c"
15402d26c39SVladimir Kotal	# end source directory with a slash in order to copy just
15502d26c39SVladimir Kotal	# directory contents, not the whole directory
15602d26c39SVladimir Kotal	$RSYNC -r -q $WDIR/ $dst
15702d26c39SVladimir Kotal	if (( $? != 0 )); then
15802d26c39SVladimir Kotal		print "failed to sync webrev directory " \
15902d26c39SVladimir Kotal		    "'$WDIR' to '$dst'"
16002d26c39SVladimir Kotal		return 1
16102d26c39SVladimir Kotal	fi
16202d26c39SVladimir Kotal
16302d26c39SVladimir Kotal	print "Done."
16402d26c39SVladimir Kotal	return 0
16502d26c39SVladimir Kotal}
16602d26c39SVladimir Kotal
16702d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
168*ba44d8a2SVladimir Kotalfunction ssh_upload
16902d26c39SVladimir Kotal{
17002d26c39SVladimir Kotal	if (( $# != 1 )); then
171*ba44d8a2SVladimir Kotal		print "ssh_upload: wrong usage"
17202d26c39SVladimir Kotal		return 1
17302d26c39SVladimir Kotal	fi
17402d26c39SVladimir Kotal
17502d26c39SVladimir Kotal	typeset dst=$1
17602d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
177*ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
17802d26c39SVladimir Kotal
179*ba44d8a2SVladimir Kotal	# if the deletion was explicitly requested there is no need
180*ba44d8a2SVladimir Kotal	# to perform it again
181*ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
18202d26c39SVladimir Kotal		# we do not care about return value because this might be
18302d26c39SVladimir Kotal		# the first time this directory is uploaded
184*ba44d8a2SVladimir Kotal		delete_webrev 0
18502d26c39SVladimir Kotal	fi
18602d26c39SVladimir Kotal
18702d26c39SVladimir Kotal	# if the supplied path is absolute we assume all directories are
18802d26c39SVladimir Kotal	# created, otherwise try to create all directories in the path
18902d26c39SVladimir Kotal	# except the last one which will be created by scp
19002d26c39SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
191*ba44d8a2SVladimir Kotal		print "  Creating dirs: \c"
19202d26c39SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
19302d26c39SVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP /tmp/$webrev_mkdir.XXX )
19402d26c39SVladimir Kotal                OLDIFS=$IFS
19502d26c39SVladimir Kotal                IFS=/
19602d26c39SVladimir Kotal                mk=
19702d26c39SVladimir Kotal                for dir in $dirs_mk; do
19802d26c39SVladimir Kotal                        if [[ -z $mk ]]; then
19902d26c39SVladimir Kotal                                mk=$dir
20002d26c39SVladimir Kotal                        else
20102d26c39SVladimir Kotal                                mk=$mk/$dir
20202d26c39SVladimir Kotal                        fi
20302d26c39SVladimir Kotal                        echo "mkdir $mk" >> $batch_file_mkdir
20402d26c39SVladimir Kotal                done
20502d26c39SVladimir Kotal                IFS=$OLDIFS
20602d26c39SVladimir Kotal		$SFTP -b $batch_file_mkdir $host_spec 2>/dev/null 1>&2
20702d26c39SVladimir Kotal		if (( $? != 0 )); then
20802d26c39SVladimir Kotal			echo "Failed to create remote directories"
20902d26c39SVladimir Kotal			rm -f $batch_file_mkdir
21002d26c39SVladimir Kotal			return 1
21102d26c39SVladimir Kotal		fi
21202d26c39SVladimir Kotal		rm -f $batch_file_mkdir
21302d26c39SVladimir Kotal		print "Done."
21402d26c39SVladimir Kotal	fi
21502d26c39SVladimir Kotal
216*ba44d8a2SVladimir Kotal	print "      Uploading: \c"
21702d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
21802d26c39SVladimir Kotal		$WDIR $dst
21902d26c39SVladimir Kotal	if (( $? != 0 )); then
22002d26c39SVladimir Kotal		print "failed to upload webrev directory" \
22102d26c39SVladimir Kotal		    "'$WDIR' to '$dst'"
22202d26c39SVladimir Kotal		return 1
22302d26c39SVladimir Kotal	fi
22402d26c39SVladimir Kotal
22502d26c39SVladimir Kotal	print "Done."
22602d26c39SVladimir Kotal	return 0
22702d26c39SVladimir Kotal}
22802d26c39SVladimir Kotal
22902d26c39SVladimir Kotal#
230*ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
231*ba44d8a2SVladimir Kotal# on failure.
232*ba44d8a2SVladimir Kotal#
233*ba44d8a2SVladimir Kotalfunction delete_webrev
234*ba44d8a2SVladimir Kotal{
235*ba44d8a2SVladimir Kotal	if (( $# != 1 )); then
236*ba44d8a2SVladimir Kotal		print "delete_webrev: wrong usage"
237*ba44d8a2SVladimir Kotal		return 1
238*ba44d8a2SVladimir Kotal	fi
239*ba44d8a2SVladimir Kotal
240*ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
241*ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
242*ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
243*ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
244*ba44d8a2SVladimir Kotal	integer -r check=$1
245*ba44d8a2SVladimir Kotal	typeset dir_rm
246*ba44d8a2SVladimir Kotal
247*ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
248*ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
249*ba44d8a2SVladimir Kotal		return 1
250*ba44d8a2SVladimir Kotal	fi
251*ba44d8a2SVladimir Kotal
252*ba44d8a2SVladimir Kotal	# Strip the ending slash.
253*ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
254*ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
255*ba44d8a2SVladimir Kotal	else
256*ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
257*ba44d8a2SVladimir Kotal	fi
258*ba44d8a2SVladimir Kotal
259*ba44d8a2SVladimir Kotal	print "Removing remote: \c"
260*ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
261*ba44d8a2SVladimir Kotal		print "empty directory for removal"
262*ba44d8a2SVladimir Kotal		return 1
263*ba44d8a2SVladimir Kotal	fi
264*ba44d8a2SVladimir Kotal
265*ba44d8a2SVladimir Kotal	# Prepare batch file.
266*ba44d8a2SVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXX )
267*ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
268*ba44d8a2SVladimir Kotal		print "Cannot create temporary file"
269*ba44d8a2SVladimir Kotal		return 1
270*ba44d8a2SVladimir Kotal	fi
271*ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
272*ba44d8a2SVladimir Kotal
273*ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
274*ba44d8a2SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>/dev/null 1>&2
275*ba44d8a2SVladimir Kotal	integer -r ret=$?
276*ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
277*ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
278*ba44d8a2SVladimir Kotal		print "Failed"
279*ba44d8a2SVladimir Kotal		return $ret
280*ba44d8a2SVladimir Kotal	fi
281*ba44d8a2SVladimir Kotal	print "Done."
282*ba44d8a2SVladimir Kotal
283*ba44d8a2SVladimir Kotal	return 0
284*ba44d8a2SVladimir Kotal}
285*ba44d8a2SVladimir Kotal
286*ba44d8a2SVladimir Kotal#
28702d26c39SVladimir Kotal# Upload webrev to remote site
28802d26c39SVladimir Kotal#
289*ba44d8a2SVladimir Kotalfunction upload_webrev
29002d26c39SVladimir Kotal{
29102d26c39SVladimir Kotal	typeset -r rsync_prefix="rsync://"
29202d26c39SVladimir Kotal	typeset -r ssh_prefix="ssh://"
29302d26c39SVladimir Kotal
29402d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
29502d26c39SVladimir Kotal		echo "webrev directory '$WDIR' does not exist"
29602d26c39SVladimir Kotal		return 1
29702d26c39SVladimir Kotal	fi
29802d26c39SVladimir Kotal
29902d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
30002d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
30102d26c39SVladimir Kotal	# target he probably knows what he is doing.
30202d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
303*ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
30402d26c39SVladimir Kotal			| $GREP closed >/dev/null
30502d26c39SVladimir Kotal		if (( $? == 0 )); then
30602d26c39SVladimir Kotal			echo "directory '$WDIR' contains \"closed\" directory"
30702d26c39SVladimir Kotal			return 1
30802d26c39SVladimir Kotal		fi
30902d26c39SVladimir Kotal	fi
31002d26c39SVladimir Kotal
31102d26c39SVladimir Kotal	# we have the URI for remote destination now so let's start the upload
31202d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
31302d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
31402d26c39SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix}
31502d26c39SVladimir Kotal			return $?
31602d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
31702d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
31802d26c39SVladimir Kotal			return $?
31902d26c39SVladimir Kotal		else
32002d26c39SVladimir Kotal			echo "invalid upload URI ($remote_target)"
32102d26c39SVladimir Kotal			return 1
32202d26c39SVladimir Kotal		fi
32302d26c39SVladimir Kotal	else
32402d26c39SVladimir Kotal		# try rsync first and fallback to SSH in case it fails
325*ba44d8a2SVladimir Kotal		rsync_upload ${remote_target}
32602d26c39SVladimir Kotal		if (( $? != 0 )); then
32702d26c39SVladimir Kotal			echo "rsync upload failed, falling back to SSH"
328*ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
32902d26c39SVladimir Kotal		fi
33002d26c39SVladimir Kotal		return $?
33102d26c39SVladimir Kotal	fi
33202d26c39SVladimir Kotal
33302d26c39SVladimir Kotal	return 0
33402d26c39SVladimir Kotal}
33502d26c39SVladimir Kotal
336daaffb31Sdp#
337daaffb31Sdp# input_cmd | html_quote | output_cmd
338daaffb31Sdp# or
339daaffb31Sdp# html_quote filename | output_cmd
3407c478bd9Sstevel@tonic-gate#
3417c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
3427c478bd9Sstevel@tonic-gate#
3437c478bd9Sstevel@tonic-gatehtml_quote()
3447c478bd9Sstevel@tonic-gate{
3457c478bd9Sstevel@tonic-gate	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
3467c478bd9Sstevel@tonic-gate}
3477c478bd9Sstevel@tonic-gate
348daaffb31Sdp#
349daaffb31Sdp# input_cmd | bug2url | output_cmd
350daaffb31Sdp#
351daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
352daaffb31Sdp#
353daaffb31Sdpbug2url()
3547c478bd9Sstevel@tonic-gate{
355daaffb31Sdp	sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
356daaffb31Sdp}
357daaffb31Sdp
3587c478bd9Sstevel@tonic-gate#
359daaffb31Sdp# input_cmd | sac2url | output_cmd
3607c478bd9Sstevel@tonic-gate#
361daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
362daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
363daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
364daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
3657c478bd9Sstevel@tonic-gate#
366daaffb31Sdpsac2url()
367daaffb31Sdp{
368e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
3690a30ef2cSstevel	    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'
370daaffb31Sdp	else
371daaffb31Sdp	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
372daaffb31Sdp	fi
373daaffb31Sdp}
374daaffb31Sdp
3757c478bd9Sstevel@tonic-gate#
376daaffb31Sdp# strip_unchanged <infile> | output_cmd
3777c478bd9Sstevel@tonic-gate#
378daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
379daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
3807c478bd9Sstevel@tonic-gate#
381daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
382daaffb31Sdp# identical lines are retained before and after the changed lines to
383daaffb31Sdp# provide some context.  The number of these lines is controlled by the
384cdf0c1d5Smjnelson# variable C in the $AWK script below.
385daaffb31Sdp#
386daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
387daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
388daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
389daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
390daaffb31Sdp#
391daaffb31Sdpstrip_unchanged()
392daaffb31Sdp{
393cdf0c1d5Smjnelson	$AWK '
394daaffb31Sdp	BEGIN	{ C = c = 20 }
395cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
396daaffb31Sdp		if (c > C) {
397daaffb31Sdp			c -= C
398daaffb31Sdp			inx = 0
399daaffb31Sdp			if (c > C) {
400cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
401daaffb31Sdp				inx = c % C
402daaffb31Sdp				c = C
403daaffb31Sdp			}
404daaffb31Sdp
405daaffb31Sdp			for (i = 0; i < c; i++)
406daaffb31Sdp				print ln[(inx + i) % C]
407daaffb31Sdp		}
408daaffb31Sdp		c = 0;
409daaffb31Sdp		print
410daaffb31Sdp		next
411daaffb31Sdp	}
412daaffb31Sdp	{	if (c >= C) {
413daaffb31Sdp			ln[c % C] = $0
414daaffb31Sdp			c++;
415daaffb31Sdp			next;
416daaffb31Sdp		}
417daaffb31Sdp		c++;
418daaffb31Sdp		print
419daaffb31Sdp	}
420cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
421daaffb31Sdp
422daaffb31Sdp	' $1
423daaffb31Sdp}
424daaffb31Sdp
425daaffb31Sdp#
426daaffb31Sdp# sdiff_to_html
427daaffb31Sdp#
428daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
429daaffb31Sdp# processes the diff output to present the files as an HTML document with
430daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
431daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
432daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
433daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
434daaffb31Sdp# e.g.
435daaffb31Sdp#
436daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
437daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
438daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
439daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
440daaffb31Sdp#          1234567</a> my bugid' > <file>.html
441daaffb31Sdp#
442daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
443daaffb31Sdp# in the webrev tree.
444daaffb31Sdp#
445daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
446daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
447daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
448daaffb31Sdp# the editing codes, e.g.
4497c478bd9Sstevel@tonic-gate#
4507c478bd9Sstevel@tonic-gate#      8c8
4517c478bd9Sstevel@tonic-gate#      57a61
4527c478bd9Sstevel@tonic-gate#      63c66,76
4537c478bd9Sstevel@tonic-gate#      68,93d80
4547c478bd9Sstevel@tonic-gate#      106d90
4557c478bd9Sstevel@tonic-gate#      108,110d91
4567c478bd9Sstevel@tonic-gate#
457daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
458daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
459daaffb31Sdp#  into something like this:
4607c478bd9Sstevel@tonic-gate#
4617c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
4627c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
463daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
4647c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
4657c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
4667c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
4677c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
4687c478bd9Sstevel@tonic-gate#        :               :
4697c478bd9Sstevel@tonic-gate#
470daaffb31Sdp#  This script is then run on the original source file to generate the
471daaffb31Sdp#  HTML that corresponds to the source file.
4727c478bd9Sstevel@tonic-gate#
473daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
474daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
475daaffb31Sdp#  notice that the changes are color-coded:
4767c478bd9Sstevel@tonic-gate#
4777c478bd9Sstevel@tonic-gate#   black     - unchanged lines
4787c478bd9Sstevel@tonic-gate#   blue      - changed lines
4797c478bd9Sstevel@tonic-gate#   bold blue - new lines
4807c478bd9Sstevel@tonic-gate#   brown     - deleted lines
4817c478bd9Sstevel@tonic-gate#
482daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
483daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
484daaffb31Sdp#  Teamware's filemerge tool.
485daaffb31Sdp#
486daaffb31Sdpsdiff_to_html()
487daaffb31Sdp{
4887c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
4897c478bd9Sstevel@tonic-gate
490daaffb31Sdp	TNAME=$3
491daaffb31Sdp	TPATH=$4
492daaffb31Sdp	COMMENT=$5
493daaffb31Sdp
4947c478bd9Sstevel@tonic-gate	#
4957c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
4967c478bd9Sstevel@tonic-gate	#
497cdf0c1d5Smjnelson	$AWK '
4987c478bd9Sstevel@tonic-gate	BEGIN	{
4997c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
500daaffb31Sdp		printf "function removed() "
501daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
502daaffb31Sdp		printf "function changed() "
503daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
504daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
5057c478bd9Sstevel@tonic-gate}
5067c478bd9Sstevel@tonic-gate	/^</	{next}
5077c478bd9Sstevel@tonic-gate	/^>/	{next}
5087c478bd9Sstevel@tonic-gate	/^---/	{next}
509daaffb31Sdp
5107c478bd9Sstevel@tonic-gate	{
5117c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
5127c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
5137c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
5147c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
5157c478bd9Sstevel@tonic-gate			if (n == 1)
5167c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
5177c478bd9Sstevel@tonic-gate			else
5187c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
5197c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
5207c478bd9Sstevel@tonic-gate			next
5217c478bd9Sstevel@tonic-gate		}
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
5247c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
5257c478bd9Sstevel@tonic-gate		s = r[1];
5267c478bd9Sstevel@tonic-gate		if (n == 1)
5277c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
5287c478bd9Sstevel@tonic-gate		else {
5297c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
5307c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
5317c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
5327c478bd9Sstevel@tonic-gate		}
5337c478bd9Sstevel@tonic-gate		next
5347c478bd9Sstevel@tonic-gate	}
5357c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
5367c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5377c478bd9Sstevel@tonic-gate		n1 = r[1]
5387c478bd9Sstevel@tonic-gate		n2 = r[2]
5397c478bd9Sstevel@tonic-gate		if (n == 1)
540daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
5417c478bd9Sstevel@tonic-gate		else
542daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
5437c478bd9Sstevel@tonic-gate		next
5447c478bd9Sstevel@tonic-gate	}
5457c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
5467c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5477c478bd9Sstevel@tonic-gate		n1 = r[1]
5487c478bd9Sstevel@tonic-gate		n2 = r[2]
5497c478bd9Sstevel@tonic-gate		final = n2
5507c478bd9Sstevel@tonic-gate		d1 = 0
5517c478bd9Sstevel@tonic-gate		if (n == 1)
552daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
5537c478bd9Sstevel@tonic-gate		else {
5547c478bd9Sstevel@tonic-gate			d1 = n2 - n1
555daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
5567c478bd9Sstevel@tonic-gate		}
5577c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
5587c478bd9Sstevel@tonic-gate		n1 = r[1]
5597c478bd9Sstevel@tonic-gate		n2 = r[2]
5607c478bd9Sstevel@tonic-gate		if (m > 1) {
5617c478bd9Sstevel@tonic-gate			d2  = n2 - n1
5627c478bd9Sstevel@tonic-gate			if (d2 > d1) {
5637c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
5647c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
5657c478bd9Sstevel@tonic-gate			}
5667c478bd9Sstevel@tonic-gate		}
5677c478bd9Sstevel@tonic-gate		printf "next}\n" ;
5687c478bd9Sstevel@tonic-gate
5697c478bd9Sstevel@tonic-gate		next
5707c478bd9Sstevel@tonic-gate	}
5717c478bd9Sstevel@tonic-gate	}
5727c478bd9Sstevel@tonic-gate
573daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
574daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate	#
5777c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
5787c478bd9Sstevel@tonic-gate	#
579cdf0c1d5Smjnelson	$AWK '
5807c478bd9Sstevel@tonic-gate	BEGIN	{
5817c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
582daaffb31Sdp		printf "function new() "
583daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
584daaffb31Sdp		printf "function changed() "
585daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
586daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
5877c478bd9Sstevel@tonic-gate	}
588daaffb31Sdp
5897c478bd9Sstevel@tonic-gate	/^</	{next}
5907c478bd9Sstevel@tonic-gate	/^>/	{next}
5917c478bd9Sstevel@tonic-gate	/^---/	{next}
592daaffb31Sdp
5937c478bd9Sstevel@tonic-gate	{
5947c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
5957c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
5967c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
5977c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
5987c478bd9Sstevel@tonic-gate			if (n == 1)
5997c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6007c478bd9Sstevel@tonic-gate			else
6017c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6027c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6037c478bd9Sstevel@tonic-gate			next
6047c478bd9Sstevel@tonic-gate		}
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
6077c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
6087c478bd9Sstevel@tonic-gate		s = r[1];
6097c478bd9Sstevel@tonic-gate		if (n == 1)
6107c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6117c478bd9Sstevel@tonic-gate		else {
6127c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6137c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6147c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6157c478bd9Sstevel@tonic-gate		}
6167c478bd9Sstevel@tonic-gate		next
6177c478bd9Sstevel@tonic-gate	}
6187c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6197c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6207c478bd9Sstevel@tonic-gate		n1 = r[1]
6217c478bd9Sstevel@tonic-gate		n2 = r[2]
6227c478bd9Sstevel@tonic-gate		if (n == 1)
623daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
6247c478bd9Sstevel@tonic-gate		else
625daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
6267c478bd9Sstevel@tonic-gate		next
6277c478bd9Sstevel@tonic-gate	}
6287c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
6297c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6307c478bd9Sstevel@tonic-gate		n1 = r[1]
6317c478bd9Sstevel@tonic-gate		n2 = r[2]
6327c478bd9Sstevel@tonic-gate		final = n2
6337c478bd9Sstevel@tonic-gate		d2 = 0;
6347c478bd9Sstevel@tonic-gate		if (n == 1) {
6357c478bd9Sstevel@tonic-gate			final = n1
636daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
6377c478bd9Sstevel@tonic-gate		} else {
6387c478bd9Sstevel@tonic-gate			d2 = n2 - n1
639daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
6407c478bd9Sstevel@tonic-gate		}
6417c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
6427c478bd9Sstevel@tonic-gate		n1 = r[1]
6437c478bd9Sstevel@tonic-gate		n2 = r[2]
6447c478bd9Sstevel@tonic-gate		if (m > 1) {
6457c478bd9Sstevel@tonic-gate			d1  = n2 - n1
6467c478bd9Sstevel@tonic-gate			if (d1 > d2) {
6477c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
6487c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
6497c478bd9Sstevel@tonic-gate			}
6507c478bd9Sstevel@tonic-gate		}
6517c478bd9Sstevel@tonic-gate		printf "next}\n" ;
6527c478bd9Sstevel@tonic-gate		next
6537c478bd9Sstevel@tonic-gate	}
6547c478bd9Sstevel@tonic-gate	}
655daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
6567c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
6577c478bd9Sstevel@tonic-gate
658daaffb31Sdp	#
659cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
660daaffb31Sdp	#
661cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
6627c478bd9Sstevel@tonic-gate
663cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
6647c478bd9Sstevel@tonic-gate
665daaffb31Sdp	#
666daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
667daaffb31Sdp	#
668daaffb31Sdp	print "$HTML<head>$STDHEAD"
669cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
670daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
671daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
672daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
673daaffb31Sdp	print "<table><tr valign=\"top\">"
674daaffb31Sdp	print "<td><pre>"
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
6777c478bd9Sstevel@tonic-gate
678daaffb31Sdp	print "</pre></td><td><pre>"
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
6817c478bd9Sstevel@tonic-gate
682daaffb31Sdp	print "</pre></td>"
683daaffb31Sdp	print "</tr></table>"
684daaffb31Sdp	print "</body></html>"
6857c478bd9Sstevel@tonic-gate
686daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
687daaffb31Sdp	    "$COMMENT"
6887c478bd9Sstevel@tonic-gate}
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate
691daaffb31Sdp#
692daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
693daaffb31Sdp#
694daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
695daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
696daaffb31Sdp# and then emit the main frame.  Content is placed into:
697daaffb31Sdp#
698daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
699daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
700daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
701daaffb31Sdp#
702daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
703daaffb31Sdp#
7047c478bd9Sstevel@tonic-gatefunction framed_sdiff
7057c478bd9Sstevel@tonic-gate{
7067c478bd9Sstevel@tonic-gate	typeset TNAME=$1
707daaffb31Sdp	typeset TPATH=$2
708daaffb31Sdp	typeset lhsfile=$3
709daaffb31Sdp	typeset rhsfile=$4
710daaffb31Sdp	typeset comments=$5
7117c478bd9Sstevel@tonic-gate	typeset RTOP
712daaffb31Sdp
7137c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
714daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
715daaffb31Sdp
716daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
717daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
718daaffb31Sdp
719daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
720cac38512Smjnelson	    <script type="text/javascript" src="$RTOP/ancnav.js"></script>
7217c478bd9Sstevel@tonic-gate	    </head>
722daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
723cac38512Smjnelson	    <a name="0"></a>
724cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
725daaffb31Sdp	EOF
726daaffb31Sdp
727daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
728daaffb31Sdp
729daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
730daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
731daaffb31Sdp
732daaffb31Sdp	close='</body></html>'
733daaffb31Sdp
734daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
735daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
736daaffb31Sdp
737daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
738daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
739daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
740daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
741daaffb31Sdp	  <frameset rows="*,60">
742daaffb31Sdp	    <frameset cols="50%,50%">
743cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
744cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
745daaffb31Sdp	    </frameset>
746daaffb31Sdp	  <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
747cac38512Smjnelson	   marginheight="0" name="nav"></frame>
748daaffb31Sdp	  <noframes>
749daaffb31Sdp            <body id="SUNWwebrev">
750daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
7517c478bd9Sstevel@tonic-gate	      and has the feature enabled.
752daaffb31Sdp            </body>
753daaffb31Sdp	  </noframes>
754daaffb31Sdp	  </frameset>
7557c478bd9Sstevel@tonic-gate	</html>
7567c478bd9Sstevel@tonic-gate	EOF
7577c478bd9Sstevel@tonic-gate}
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate
760daaffb31Sdp#
761daaffb31Sdp# fix_postscript
762daaffb31Sdp#
763daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
764daaffb31Sdp# 	- removing all extraneous headers/trailers
765daaffb31Sdp#	- making the page numbers right
766daaffb31Sdp#	- removing pages devoid of contents which confuse some
767daaffb31Sdp#	  postscript readers.
768daaffb31Sdp#
769daaffb31Sdp# From Casper.
770daaffb31Sdp#
771daaffb31Sdpfunction fix_postscript
7727c478bd9Sstevel@tonic-gate{
773daaffb31Sdp	infile=$1
7747c478bd9Sstevel@tonic-gate
775daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
7767c478bd9Sstevel@tonic-gate
777daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
778daaffb31Sdp	print "%%Orientation: Landscape\n";
7797c478bd9Sstevel@tonic-gate
780daaffb31Sdp	$pno = 0;
781daaffb31Sdp	$doprint = 1;
782daaffb31Sdp
783daaffb31Sdp	$page = "";
784daaffb31Sdp
785daaffb31Sdp	while (<>) {
786daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
787daaffb31Sdp
788daaffb31Sdp		if (/^%%Page:/) {
789daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
790daaffb31Sdp				# Header or single page containing text
791daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
792daaffb31Sdp				print $page;
793daaffb31Sdp				$pno++;
794daaffb31Sdp			} else {
795daaffb31Sdp				# Empty page, skip it.
7967c478bd9Sstevel@tonic-gate			}
797daaffb31Sdp			$page = "";
798daaffb31Sdp			$doprint = 1;
7997c478bd9Sstevel@tonic-gate			next;
8007c478bd9Sstevel@tonic-gate		}
8017c478bd9Sstevel@tonic-gate
802daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
803daaffb31Sdp		# %%Page of the next
804daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
805daaffb31Sdp		$page .= $_ if ($doprint);
8067c478bd9Sstevel@tonic-gate	}
8077c478bd9Sstevel@tonic-gate
808daaffb31Sdp	if ($page =~ /\)S/) {
809daaffb31Sdp		print "%%Page: ? $pno\n";
810daaffb31Sdp		print $page;
811daaffb31Sdp	} else {
812daaffb31Sdp		$pno--;
813daaffb31Sdp	}
814daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
815daaffb31SdpEOF
816daaffb31Sdp
81714983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
818daaffb31Sdp}
819daaffb31Sdp
820daaffb31Sdp
821daaffb31Sdp#
822daaffb31Sdp# input_cmd | insert_anchors | output_cmd
823daaffb31Sdp#
8247c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
825daaffb31Sdp# anchors.  These are used to drive the frames version of the
8267c478bd9Sstevel@tonic-gate# sdiffs output.
8277c478bd9Sstevel@tonic-gate#
8287c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
8297c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
8307c478bd9Sstevel@tonic-gate#
831daaffb31Sdp# The script detects changed lines as any line that has a "<span
832daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
833daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
8347c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
8357c478bd9Sstevel@tonic-gate# deleted.
8367c478bd9Sstevel@tonic-gate#
837daaffb31Sdpfunction insert_anchors
838daaffb31Sdp{
839cdf0c1d5Smjnelson	$AWK '
8407c478bd9Sstevel@tonic-gate	function ia() {
841daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
8427c478bd9Sstevel@tonic-gate	}
843daaffb31Sdp
8447c478bd9Sstevel@tonic-gate	BEGIN {
845daaffb31Sdp		anc=1;
8467c478bd9Sstevel@tonic-gate		inblock=1;
847daaffb31Sdp		printf "<pre>\n";
8487c478bd9Sstevel@tonic-gate	}
849daaffb31Sdp	NF == 0 || /^<span class=/ {
8507c478bd9Sstevel@tonic-gate		if (inblock == 0) {
8517c478bd9Sstevel@tonic-gate			ia();
8527c478bd9Sstevel@tonic-gate			inblock=1;
8537c478bd9Sstevel@tonic-gate		}
8547c478bd9Sstevel@tonic-gate		print;
8557c478bd9Sstevel@tonic-gate		next;
8567c478bd9Sstevel@tonic-gate	}
8577c478bd9Sstevel@tonic-gate	{
8587c478bd9Sstevel@tonic-gate		inblock=0;
8597c478bd9Sstevel@tonic-gate		print;
8607c478bd9Sstevel@tonic-gate	}
8617c478bd9Sstevel@tonic-gate	END {
8627c478bd9Sstevel@tonic-gate		ia();
863daaffb31Sdp
864daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
865daaffb31Sdp		printf "--- EOF ---</b>"
8667c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
867daaffb31Sdp		printf "</pre>"
868daaffb31Sdp		printf "<form name=\"eof\">";
869cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
870cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
871daaffb31Sdp		printf "</form>";
8727c478bd9Sstevel@tonic-gate	}
8737c478bd9Sstevel@tonic-gate	' $1
8747c478bd9Sstevel@tonic-gate}
8757c478bd9Sstevel@tonic-gate
8767c478bd9Sstevel@tonic-gate
877daaffb31Sdp#
878daaffb31Sdp# relative_dir
879daaffb31Sdp#
880daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
881daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
882daaffb31Sdp# this function would print "../../../../".
883daaffb31Sdp#
884daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
885daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
886daaffb31Sdp# is not relocatable.
887daaffb31Sdp#
888daaffb31Sdpfunction relative_dir
8897c478bd9Sstevel@tonic-gate{
890daaffb31Sdp	typeset cur="${1##$2?(/)}"
891daaffb31Sdp	typeset ret=""
892daaffb31Sdp	if [[ $2 == $cur ]]; then   # Should never happen.
893daaffb31Sdp		# Should never happen.
89414983201Sdp		print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
895daaffb31Sdp		print -u2 "to \"$2\".  Check input paths.  Framed webrev "
896daaffb31Sdp		print -u2 "will not be relocatable!"
897daaffb31Sdp		print $2
898daaffb31Sdp		return
899daaffb31Sdp	fi
900daaffb31Sdp
901daaffb31Sdp	while [[ -n ${cur} ]];
9027c478bd9Sstevel@tonic-gate	do
9037c478bd9Sstevel@tonic-gate		cur=${cur%%*(/)*([!/])}
904daaffb31Sdp		if [[ -z $ret ]]; then
905daaffb31Sdp			ret=".."
906daaffb31Sdp		else
9077c478bd9Sstevel@tonic-gate			ret="../$ret"
908daaffb31Sdp		fi
9097c478bd9Sstevel@tonic-gate	done
9107c478bd9Sstevel@tonic-gate	print $ret
9117c478bd9Sstevel@tonic-gate}
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate
914daaffb31Sdp#
915daaffb31Sdp# frame_nav_js
916daaffb31Sdp#
917daaffb31Sdp# Emit javascript for frame navigation
918daaffb31Sdp#
919daaffb31Sdpfunction frame_nav_js
9207c478bd9Sstevel@tonic-gate{
9217c478bd9Sstevel@tonic-gatecat << \EOF
9227c478bd9Sstevel@tonic-gatevar myInt;
9237c478bd9Sstevel@tonic-gatevar scrolling=0;
924daaffb31Sdpvar sfactor = 3;
9257c478bd9Sstevel@tonic-gatevar scount=10;
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gatefunction scrollByPix() {
9287c478bd9Sstevel@tonic-gate	if (scount<=0) {
9297c478bd9Sstevel@tonic-gate		sfactor*=1.2;
9307c478bd9Sstevel@tonic-gate		scount=10;
9317c478bd9Sstevel@tonic-gate	}
9327c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
9337c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
9347c478bd9Sstevel@tonic-gate	scount--;
9357c478bd9Sstevel@tonic-gate}
9367c478bd9Sstevel@tonic-gate
937daaffb31Sdpfunction scrollToAnc(num) {
938daaffb31Sdp
939daaffb31Sdp	// Update the value of the anchor in the form which we use as
940daaffb31Sdp	// storage for this value.  setAncValue() will take care of
941daaffb31Sdp	// correcting for overflow and underflow of the value and return
942daaffb31Sdp	// us the new value.
943daaffb31Sdp	num = setAncValue(num);
944daaffb31Sdp
945daaffb31Sdp	// Set location and scroll back a little to expose previous
946daaffb31Sdp	// lines.
947daaffb31Sdp	//
948daaffb31Sdp	// Note that this could be improved: it is possible although
949daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
950daaffb31Sdp	// scroll to that location directly.
951daaffb31Sdp	//
9527c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
9537c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
954daaffb31Sdp
9557c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
9567c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
9577c478bd9Sstevel@tonic-gate}
9587c478bd9Sstevel@tonic-gate
959daaffb31Sdpfunction getAncValue()
960daaffb31Sdp{
961daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
962daaffb31Sdp}
963daaffb31Sdp
964daaffb31Sdpfunction setAncValue(val)
965daaffb31Sdp{
966daaffb31Sdp	if (val <= 0) {
967daaffb31Sdp		val = 0;
968daaffb31Sdp		parent.nav.document.diff.real.value = val;
969daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
970daaffb31Sdp		return (val);
971daaffb31Sdp	}
972daaffb31Sdp
973daaffb31Sdp	//
974daaffb31Sdp	// The way we compute the max anchor value is to stash it
975daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
976daaffb31Sdp	// on each side, so we pluck from the left.
977daaffb31Sdp	//
978daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
979daaffb31Sdp	if (val < maxval) {
980daaffb31Sdp		parent.nav.document.diff.real.value = val;
981daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
982daaffb31Sdp		return (val);
983daaffb31Sdp	}
984daaffb31Sdp
985daaffb31Sdp	// this must be: val >= maxval
986daaffb31Sdp	val = maxval;
987daaffb31Sdp	parent.nav.document.diff.real.value = val;
988daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
989daaffb31Sdp	return (val);
990daaffb31Sdp}
991daaffb31Sdp
9927c478bd9Sstevel@tonic-gatefunction stopScroll() {
9937c478bd9Sstevel@tonic-gate	if (scrolling==1) {
9947c478bd9Sstevel@tonic-gate		clearInterval(myInt);
9957c478bd9Sstevel@tonic-gate		scrolling=0;
9967c478bd9Sstevel@tonic-gate	}
9977c478bd9Sstevel@tonic-gate}
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gatefunction startScroll() {
10007c478bd9Sstevel@tonic-gate	stopScroll();
10017c478bd9Sstevel@tonic-gate	scrolling=1;
10027c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
10037c478bd9Sstevel@tonic-gate}
10047c478bd9Sstevel@tonic-gate
10057c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1006daaffb31Sdp
10077c478bd9Sstevel@tonic-gate	switch (b) {
10087c478bd9Sstevel@tonic-gate	    case 1 :
1009daaffb31Sdp		scrollToAnc(-1);
10107c478bd9Sstevel@tonic-gate		break;
10117c478bd9Sstevel@tonic-gate	    case 2 :
1012daaffb31Sdp		scrollToAnc(getAncValue() - 1);
10137c478bd9Sstevel@tonic-gate		break;
10147c478bd9Sstevel@tonic-gate	    case 3 :
10157c478bd9Sstevel@tonic-gate		sfactor=-3;
10167c478bd9Sstevel@tonic-gate		startScroll();
10177c478bd9Sstevel@tonic-gate		break;
10187c478bd9Sstevel@tonic-gate	    case 4 :
10197c478bd9Sstevel@tonic-gate		sfactor=3;
10207c478bd9Sstevel@tonic-gate		startScroll();
10217c478bd9Sstevel@tonic-gate		break;
10227c478bd9Sstevel@tonic-gate	    case 5 :
1023daaffb31Sdp		scrollToAnc(getAncValue() + 1);
10247c478bd9Sstevel@tonic-gate		break;
10257c478bd9Sstevel@tonic-gate	    case 6 :
1026daaffb31Sdp		scrollToAnc(999999);
10277c478bd9Sstevel@tonic-gate		break;
10287c478bd9Sstevel@tonic-gate	}
10297c478bd9Sstevel@tonic-gate}
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
10327c478bd9Sstevel@tonic-gate	stopScroll();
10337c478bd9Sstevel@tonic-gate}
10347c478bd9Sstevel@tonic-gate
1035daaffb31Sdpfunction keypress(ev) {
1036daaffb31Sdp	var keynum;
1037daaffb31Sdp	var keychar;
1038daaffb31Sdp
1039daaffb31Sdp	if (window.event) { // IE
1040daaffb31Sdp		keynum = ev.keyCode;
1041daaffb31Sdp	} else if (ev.which) { // non-IE
1042daaffb31Sdp		keynum = ev.which;
1043daaffb31Sdp	}
1044daaffb31Sdp
1045daaffb31Sdp	keychar = String.fromCharCode(keynum);
1046daaffb31Sdp
1047daaffb31Sdp	if (keychar == "k") {
1048daaffb31Sdp		handlePress(2);
1049daaffb31Sdp		return (0);
1050daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1051daaffb31Sdp		handlePress(5);
1052daaffb31Sdp		return (0);
1053daaffb31Sdp	}
1054daaffb31Sdp	return (1);
1055daaffb31Sdp}
1056daaffb31Sdp
10577c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1058daaffb31Sdp	val = parent.nav.document.diff.display.value;
1059daaffb31Sdp	if (val == "EOF") {
1060daaffb31Sdp		scrollToAnc(999999);
1061daaffb31Sdp		return;
1062daaffb31Sdp	}
1063daaffb31Sdp
1064daaffb31Sdp	if (val == "BOF") {
1065daaffb31Sdp		scrollToAnc(0);
1066daaffb31Sdp		return;
1067daaffb31Sdp	}
1068daaffb31Sdp
1069daaffb31Sdp        i=parseInt(val);
10707c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1071daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
10727c478bd9Sstevel@tonic-gate        } else {
1073daaffb31Sdp                scrollToAnc(i);
10747c478bd9Sstevel@tonic-gate        }
10757c478bd9Sstevel@tonic-gate        return false;
10767c478bd9Sstevel@tonic-gate}
10777c478bd9Sstevel@tonic-gate
1078daaffb31SdpEOF
1079daaffb31Sdp}
1080daaffb31Sdp
1081daaffb31Sdp#
1082daaffb31Sdp# frame_navigation
1083daaffb31Sdp#
1084daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1085daaffb31Sdp#
1086daaffb31Sdpfunction frame_navigation
1087daaffb31Sdp{
1088daaffb31Sdp	print "$HTML<head>$STDHEAD"
1089daaffb31Sdp
1090daaffb31Sdp	cat << \EOF
1091daaffb31Sdp<title>Anchor Navigation</title>
1092daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1093daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1094daaffb31Sdp
1095daaffb31Sdp<style type="text/css">
1096daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1097daaffb31Sdp		    background-color: #eee; text-align: center;
1098daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1099daaffb31Sdp    div.button a { font-weight: bold; color: black }
1100daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1101daaffb31Sdp</style>
1102daaffb31SdpEOF
1103daaffb31Sdp
1104cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1105daaffb31Sdp
1106daaffb31Sdp	cat << \EOF
11077c478bd9Sstevel@tonic-gate</head>
1108daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1109daaffb31Sdp	onkeypress="keypress(event);">
11107c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
11117c478bd9Sstevel@tonic-gate      <center>
1112cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
11137c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
11147c478bd9Sstevel@tonic-gate      </center>
11157c478bd9Sstevel@tonic-gate    </noscript>
11167c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1117daaffb31Sdp	<tr>
1118daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1119daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1120daaffb31Sdp          at right</td>
1121daaffb31Sdp	  <td align="center" valign="top" width="50%">
11227c478bd9Sstevel@tonic-gate	    <div class="button">
1123daaffb31Sdp	      <table border="0" align="center">
1124daaffb31Sdp                  <tr>
1125daaffb31Sdp		    <td>
11267c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
11277c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
11287c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
11297c478bd9Sstevel@tonic-gate			 onClick="return false;"
11307c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1131daaffb31Sdp		    <td>
11327c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
11337c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
11347c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
11357c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1136daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1137daaffb31Sdp		    <td>
11387c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
11397c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
11407c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
11417c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
11427c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
11437c478bd9Sstevel@tonic-gate		    </td></tr>
1144daaffb31Sdp
11457c478bd9Sstevel@tonic-gate		  <tr>
1146daaffb31Sdp		    <td>
11477c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
11487c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
11497c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
11507c478bd9Sstevel@tonic-gate			 onClick="return false;"
11517c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1152daaffb31Sdp		    <td>
11537c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
11547c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
11557c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
11567c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1157daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1158daaffb31Sdp		    <td>
11597c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
11607c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
11617c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
11627c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
11637c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1164daaffb31Sdp		  </tr>
1165daaffb31Sdp              </table>
1166daaffb31Sdp	    </div>
1167daaffb31Sdp	  </td>
11687c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1169daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1170cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1171cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
11727c478bd9Sstevel@tonic-gate	    </form>
11737c478bd9Sstevel@tonic-gate	  </th>
1174daaffb31Sdp	</tr>
11757c478bd9Sstevel@tonic-gate    </table>
11767c478bd9Sstevel@tonic-gate  </body>
11777c478bd9Sstevel@tonic-gate</html>
11787c478bd9Sstevel@tonic-gateEOF
11797c478bd9Sstevel@tonic-gate}
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate
1182daaffb31Sdp
1183daaffb31Sdp#
1184daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1185daaffb31Sdp#
1186daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1187daaffb31Sdp# context or unified diffs.
1188daaffb31Sdp#
11897c478bd9Sstevel@tonic-gatediff_to_html()
11907c478bd9Sstevel@tonic-gate{
11917c478bd9Sstevel@tonic-gate	TNAME=$1
1192daaffb31Sdp	TPATH=$2
1193daaffb31Sdp	DIFFTYPE=$3
1194daaffb31Sdp	COMMENT=$4
1195daaffb31Sdp
1196daaffb31Sdp	print "$HTML<head>$STDHEAD"
1197daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1198daaffb31Sdp
1199daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1200daaffb31Sdp		print "$UDIFFCSS"
1201daaffb31Sdp	fi
1202daaffb31Sdp
1203daaffb31Sdp	cat <<-EOF
1204daaffb31Sdp	</head>
1205daaffb31Sdp	<body id="SUNWwebrev">
1206daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1207daaffb31Sdp	<pre>$COMMENT</pre>
1208daaffb31Sdp        <pre>
1209daaffb31Sdp	EOF
12107c478bd9Sstevel@tonic-gate
1211cdf0c1d5Smjnelson	html_quote | $AWK '
1212daaffb31Sdp	/^--- new/	{ next }
1213daaffb31Sdp	/^\+\+\+ new/	{ next }
1214daaffb31Sdp	/^--- old/	{ next }
1215daaffb31Sdp	/^\*\*\* old/	{ next }
1216daaffb31Sdp	/^\*\*\*\*/	{ next }
12177c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1218cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1219daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1220daaffb31Sdp			  next}
1221daaffb31Sdp
1222cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1223daaffb31Sdp			  next}
1224daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1225daaffb31Sdp			  next}
1226daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1227daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1228daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1229daaffb31Sdp			{printf "%s\n", $0; next}
12307c478bd9Sstevel@tonic-gate	'
1231daaffb31Sdp
1232daaffb31Sdp	print "</pre></body></html>\n"
12337c478bd9Sstevel@tonic-gate}
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate
1236daaffb31Sdp#
1237daaffb31Sdp# source_to_html { new | old } <filename>
1238daaffb31Sdp#
1239daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1240daaffb31Sdp#
12417c478bd9Sstevel@tonic-gatesource_to_html()
12427c478bd9Sstevel@tonic-gate{
12437c478bd9Sstevel@tonic-gate	WHICH=$1
12447c478bd9Sstevel@tonic-gate	TNAME=$2
12457c478bd9Sstevel@tonic-gate
1246daaffb31Sdp	print "$HTML<head>$STDHEAD"
1247cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1248daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1249daaffb31Sdp	print "<pre>"
1250cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1251daaffb31Sdp	print "</pre></body></html>"
12527c478bd9Sstevel@tonic-gate}
12537c478bd9Sstevel@tonic-gate
1254daaffb31Sdp#
1255cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1256daaffb31Sdp#
1257daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1258daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1259daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1260daaffb31Sdp# delta in that list (the first delta unique to the child).
12617c478bd9Sstevel@tonic-gate#
12627c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1263daaffb31Sdp#
1264daaffb31Sdpcomments_from_teamware()
12657c478bd9Sstevel@tonic-gate{
1266daaffb31Sdp	fmt=$1
1267daaffb31Sdp	pfile=$PWS/$2
1268daaffb31Sdp	cfile=$CWS/$3
12697c478bd9Sstevel@tonic-gate
1270cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1271cdf0c1d5Smjnelson		pfile=$RWS/$2
1272cdf0c1d5Smjnelson	fi
1273cdf0c1d5Smjnelson
1274daaffb31Sdp	if [[ -f $pfile ]]; then
1275cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
12767c478bd9Sstevel@tonic-gate	else
12777c478bd9Sstevel@tonic-gate		psid=1.1
12787c478bd9Sstevel@tonic-gate	fi
12797c478bd9Sstevel@tonic-gate
1280cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
12817c478bd9Sstevel@tonic-gate	N=${#sids[@]}
12827c478bd9Sstevel@tonic-gate
1283daaffb31Sdp	nawkprg='
1284daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1285daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1286daaffb31Sdp		NF == 0u	{ continue }
1287daaffb31Sdp		{if (p==0) continue; print $0 }'
1288daaffb31Sdp
12897c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
12907c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
12917c478bd9Sstevel@tonic-gate
1292daaffb31Sdp		if [[ $fmt == "text" ]]; then
1293cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1294cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1295daaffb31Sdp			return
1296daaffb31Sdp		fi
1297daaffb31Sdp
1298cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1299cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
13007c478bd9Sstevel@tonic-gate	fi
13017c478bd9Sstevel@tonic-gate}
13027c478bd9Sstevel@tonic-gate
1303daaffb31Sdp#
1304cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1305daaffb31Sdp#
1306cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1307cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1308cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1309cdf0c1d5Smjnelson# are turned into URLs.
1310cdf0c1d5Smjnelson#
1311cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1312daaffb31Sdp#
1313daaffb31Sdpcomments_from_wx()
13147c478bd9Sstevel@tonic-gate{
1315daaffb31Sdp	typeset fmt=$1
1316daaffb31Sdp	typeset p=$2
13177c478bd9Sstevel@tonic-gate
1318cdf0c1d5Smjnelson	comm=`$AWK '
1319daaffb31Sdp	$1 == "'$p'" {
13207c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
13217c478bd9Sstevel@tonic-gate		getline
13227c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
13237c478bd9Sstevel@tonic-gate		exit
1324daaffb31Sdp	}' < $wxfile`
1325daaffb31Sdp
1326cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1327cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1328cdf0c1d5Smjnelson	fi
1329cdf0c1d5Smjnelson
1330daaffb31Sdp	if [[ $fmt == "text" ]]; then
1331cdf0c1d5Smjnelson		print -- "$comm"
1332daaffb31Sdp		return
1333daaffb31Sdp	fi
1334daaffb31Sdp
1335cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1336cdf0c1d5Smjnelson
13377c478bd9Sstevel@tonic-gate}
13387c478bd9Sstevel@tonic-gate
13397c478bd9Sstevel@tonic-gate#
1340daaffb31Sdp# getcomments {text|html} filepath parentpath
1341daaffb31Sdp#
1342daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1343daaffb31Sdp#
1344daaffb31Sdpgetcomments()
1345daaffb31Sdp{
1346daaffb31Sdp	typeset fmt=$1
1347daaffb31Sdp	typeset p=$2
1348daaffb31Sdp	typeset pp=$3
13497c478bd9Sstevel@tonic-gate
13503df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
13513df69ef3SDarren Moffat		return
13523df69ef3SDarren Moffat	fi
1353cdf0c1d5Smjnelson	#
1354cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1355cdf0c1d5Smjnelson	# will be used there, too
1356cdf0c1d5Smjnelson	#
1357daaffb31Sdp	if [[ -n $wxfile ]]; then
1358daaffb31Sdp		comments_from_wx $fmt $p
1359daaffb31Sdp	else
1360daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1361daaffb31Sdp			comments_from_teamware $fmt $pp $p
1362daaffb31Sdp		fi
1363daaffb31Sdp	fi
1364daaffb31Sdp}
1365daaffb31Sdp
1366daaffb31Sdp#
1367daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1368daaffb31Sdp#
1369daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1370daaffb31Sdp#
1371daaffb31Sdpfunction printCI
1372daaffb31Sdp{
1373daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1374daaffb31Sdp	typeset str
1375daaffb31Sdp	if (( tot == 1 )); then
1376daaffb31Sdp		str="line"
1377daaffb31Sdp	else
1378daaffb31Sdp		str="lines"
1379daaffb31Sdp	fi
1380daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1381daaffb31Sdp	    $tot $str $ins $del $mod $unc
1382daaffb31Sdp}
1383daaffb31Sdp
1384daaffb31Sdp
1385daaffb31Sdp#
1386daaffb31Sdp# difflines <oldfile> <newfile>
1387daaffb31Sdp#
1388daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1389daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1390daaffb31Sdp#
13917c478bd9Sstevel@tonic-gatefunction difflines
13927c478bd9Sstevel@tonic-gate{
1393daaffb31Sdp	integer tot mod del ins unc err
13947c478bd9Sstevel@tonic-gate	typeset filename
13957c478bd9Sstevel@tonic-gate
1396cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1397daaffb31Sdp	# Change range of lines: N,Nc
13987c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
13997c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
14007c478bd9Sstevel@tonic-gate		if (n != 2) {
14017c478bd9Sstevel@tonic-gate		    error=2
14027c478bd9Sstevel@tonic-gate		    exit;
14037c478bd9Sstevel@tonic-gate		}
1404daaffb31Sdp		#
1405daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1406daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1407daaffb31Sdp		#
14087c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1409daaffb31Sdp
1410daaffb31Sdp		#
1411daaffb31Sdp		# Now count replacement lines: each represents a change instead
1412daaffb31Sdp		# of a delete, so increment c and decrement r.
1413daaffb31Sdp		#
14147c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
14157c478bd9Sstevel@tonic-gate			c++;
14167c478bd9Sstevel@tonic-gate			r--;
14177c478bd9Sstevel@tonic-gate		}
1418daaffb31Sdp		#
1419daaffb31Sdp		# If there were more replacement lines than original lines,
1420daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1421daaffb31Sdp		# but there are r changes that should be counted as adds, and
1422daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1423daaffb31Sdp		#
14247c478bd9Sstevel@tonic-gate		if (r < 0) {
14257c478bd9Sstevel@tonic-gate			a-=r;
14267c478bd9Sstevel@tonic-gate			c+=r;
14277c478bd9Sstevel@tonic-gate		}
1428daaffb31Sdp
1429daaffb31Sdp		#
1430daaffb31Sdp		# If there were more original lines than replacement lines, then
1431daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1432daaffb31Sdp		#
14337c478bd9Sstevel@tonic-gate		if (r > 0) {
14347c478bd9Sstevel@tonic-gate			d+=r;
14357c478bd9Sstevel@tonic-gate		}
14367c478bd9Sstevel@tonic-gate		next;
14377c478bd9Sstevel@tonic-gate	}
14387c478bd9Sstevel@tonic-gate
1439daaffb31Sdp	# Change lines: Nc
14407c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1441daaffb31Sdp		# The first line is a replacement; any more are additions.
14427c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
14437c478bd9Sstevel@tonic-gate			c++;
14447c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
14457c478bd9Sstevel@tonic-gate		}
14467c478bd9Sstevel@tonic-gate		next;
14477c478bd9Sstevel@tonic-gate	}
14487c478bd9Sstevel@tonic-gate
1449daaffb31Sdp	# Add lines: both Na and N,Na
14507c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
14517c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
14527c478bd9Sstevel@tonic-gate		next;
14537c478bd9Sstevel@tonic-gate	}
14547c478bd9Sstevel@tonic-gate
1455daaffb31Sdp	# Delete range of lines: N,Nd
14567c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
14577c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
14587c478bd9Sstevel@tonic-gate		if (n != 2) {
14597c478bd9Sstevel@tonic-gate			error=2
14607c478bd9Sstevel@tonic-gate			exit;
14617c478bd9Sstevel@tonic-gate		}
1462daaffb31Sdp		#
1463daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1464daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1465daaffb31Sdp		#
14667c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
14677c478bd9Sstevel@tonic-gate		d+=r;
14687c478bd9Sstevel@tonic-gate		next;
14697c478bd9Sstevel@tonic-gate	}
14707c478bd9Sstevel@tonic-gate
1471daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
14727c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
14737c478bd9Sstevel@tonic-gate
1474daaffb31Sdp	# Should not get here!
14757c478bd9Sstevel@tonic-gate	{
14767c478bd9Sstevel@tonic-gate		error=1;
14777c478bd9Sstevel@tonic-gate		exit;
14787c478bd9Sstevel@tonic-gate	}
14797c478bd9Sstevel@tonic-gate
1480daaffb31Sdp	# Finish off - print results
14817c478bd9Sstevel@tonic-gate	END {
1482daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
14837c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
14847c478bd9Sstevel@tonic-gate	}' )
14857c478bd9Sstevel@tonic-gate
1486cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
14877c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1488daaffb31Sdp		print "Unexpected Error occurred reading" \
1489daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1490daaffb31Sdp		return
1491daaffb31Sdp	fi
1492daaffb31Sdp
14937c478bd9Sstevel@tonic-gate	# Accumulate totals
14947c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1495daaffb31Sdp	(( TMOD += mod ))
14967c478bd9Sstevel@tonic-gate	(( TDEL += del ))
14977c478bd9Sstevel@tonic-gate	(( TINS += ins ))
14987c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1499cdf0c1d5Smjnelson	unc=`wc -l < $1`
15007c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1501daaffb31Sdp		(( unc -= del + mod ))
15027c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
15037c478bd9Sstevel@tonic-gate	fi
15047c478bd9Sstevel@tonic-gate	# print summary
1505daaffb31Sdp	print "<span class=\"lineschanged\">"
1506daaffb31Sdp	printCI $tot $ins $del $mod $unc
1507daaffb31Sdp	print "</span>"
15087c478bd9Sstevel@tonic-gate}
15097c478bd9Sstevel@tonic-gate
1510daaffb31Sdp
15117c478bd9Sstevel@tonic-gate#
1512daaffb31Sdp# flist_from_wx
1513daaffb31Sdp#
1514daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1515daaffb31Sdp# Sets the global 'wxfile' variable.
1516daaffb31Sdp#
1517daaffb31Sdpfunction flist_from_wx
15187c478bd9Sstevel@tonic-gate{
1519daaffb31Sdp	typeset argfile=$1
1520daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1521daaffb31Sdp		#
1522daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1523daaffb31Sdp		# because the webrev does a "cd" later on.
1524daaffb31Sdp		#
1525daaffb31Sdp		wxfile=$PWD/$argfile
15267c478bd9Sstevel@tonic-gate	else
1527daaffb31Sdp		wxfile=$argfile
15287c478bd9Sstevel@tonic-gate	fi
15297c478bd9Sstevel@tonic-gate
1530cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
15317c478bd9Sstevel@tonic-gate	  while (getline) {
15327c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
15337c478bd9Sstevel@tonic-gate		if (c > 0) print
15347c478bd9Sstevel@tonic-gate	  }
1535daaffb31Sdp	}' $wxfile > $FLIST
15367c478bd9Sstevel@tonic-gate
1537daaffb31Sdp	print " Done."
1538daaffb31Sdp}
15397c478bd9Sstevel@tonic-gate
1540daaffb31Sdp#
1541daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1542daaffb31Sdp#
1543daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1544daaffb31Sdp# names may come from the "update/create" messages and others from the
1545daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1546daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1547daaffb31Sdp# -n as well, but remove them if they are already defined.
1548daaffb31Sdp#
1549daaffb31Sdpfunction flist_from_teamware
1550daaffb31Sdp{
1551cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1552daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1553daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1554daaffb31Sdp			    "valid teamware workspace"
15557c478bd9Sstevel@tonic-gate			exit 1
15567c478bd9Sstevel@tonic-gate		fi
1557daaffb31Sdp		parent_args="-p $codemgr_parent"
15587c478bd9Sstevel@tonic-gate	fi
15597c478bd9Sstevel@tonic-gate
1560daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
15617c478bd9Sstevel@tonic-gate
1562daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1563cdf0c1d5Smjnelson	    $AWK '
1564daaffb31Sdp		/^update:|^create:/	{print $2}
1565daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1566daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1567daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1568daaffb31Sdp		NF == 0			{p=0 ; continue}
1569daaffb31Sdp		/^rename/		{old=$3}
1570daaffb31Sdp		$1 == "to:"		{print $2, old}
1571daaffb31Sdp		/^"/			{continue}
1572daaffb31Sdp		p == 1			{print $1}' |
1573daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
15747c478bd9Sstevel@tonic-gate
1575daaffb31Sdp	print " Done."
1576daaffb31Sdp}
1577daaffb31Sdp
1578cdf0c1d5Smjnelson#
1579cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1580cdf0c1d5Smjnelson#
1581cdf0c1d5Smjnelsonfunction hg_active_wxfile
1582cdf0c1d5Smjnelson{
1583cdf0c1d5Smjnelson	typeset child=$1
1584cdf0c1d5Smjnelson	typeset parent=$2
1585cdf0c1d5Smjnelson
1586cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
15879a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1588cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1589cdf0c1d5Smjnelson}
1590cdf0c1d5Smjnelson
1591cdf0c1d5Smjnelson#
1592cdf0c1d5Smjnelson# flist_from_mercurial
1593cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1594cdf0c1d5Smjnelson# flist_from_wx
1595cdf0c1d5Smjnelson#
1596cdf0c1d5Smjnelsonfunction flist_from_mercurial
1597cdf0c1d5Smjnelson{
1598cdf0c1d5Smjnelson	typeset child=$1
1599cdf0c1d5Smjnelson	typeset parent=$2
1600cdf0c1d5Smjnelson
1601cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1602cdf0c1d5Smjnelson
1603cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1604cdf0c1d5Smjnelson		print		# Blank line for the \c above
1605cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1606cdf0c1d5Smjnelson		exit 1
1607cdf0c1d5Smjnelson	fi
1608cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1609cdf0c1d5Smjnelson
1610cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1611cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1612cdf0c1d5Smjnelson}
1613cdf0c1d5Smjnelson
1614cdf0c1d5Smjnelson#
1615cdf0c1d5Smjnelson# flist_from_subversion
1616cdf0c1d5Smjnelson#
1617cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1618cdf0c1d5Smjnelson#
1619cdf0c1d5Smjnelsonfunction flist_from_subversion
1620cdf0c1d5Smjnelson{
1621cdf0c1d5Smjnelson	CWS=$1
1622cdf0c1d5Smjnelson	OLDPWD=$2
1623cdf0c1d5Smjnelson
1624cdf0c1d5Smjnelson	cd $CWS
1625cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1626cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1627cdf0c1d5Smjnelson	print -u2 " Done."
1628cdf0c1d5Smjnelson	cd $OLDPWD
1629cdf0c1d5Smjnelson}
1630cdf0c1d5Smjnelson
1631daaffb31Sdpfunction env_from_flist
1632daaffb31Sdp{
1633daaffb31Sdp	[[ -r $FLIST ]] || return
1634daaffb31Sdp
1635daaffb31Sdp	#
1636daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1637daaffb31Sdp	# list.  Then copy those into our local versions of those
1638daaffb31Sdp	# variables if they have not been set already.
1639daaffb31Sdp	#
164002d26c39SVladimir Kotal	eval `sed -e "s/#.*$//" $FLIST | $GREP = `
16417c478bd9Sstevel@tonic-gate
1642cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1643cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1644cdf0c1d5Smjnelson		export CODEMGR_WS
1645cdf0c1d5Smjnelson	fi
16467c478bd9Sstevel@tonic-gate
1647daaffb31Sdp	#
1648daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1649daaffb31Sdp	#
1650cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1651daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1652cdf0c1d5Smjnelson		export CODEMGR_PARENT
1653daaffb31Sdp	fi
1654daaffb31Sdp}
1655daaffb31Sdp
165614983201Sdpfunction look_for_prog
165714983201Sdp{
165814983201Sdp	typeset path
165914983201Sdp	typeset ppath
166014983201Sdp	typeset progname=$1
166114983201Sdp
166214983201Sdp	ppath=$PATH
166314983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
166414983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1665cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
166614983201Sdp
166714983201Sdp	PATH=$ppath prog=`whence $progname`
166814983201Sdp	if [[ -n $prog ]]; then
166914983201Sdp		print $prog
167014983201Sdp	fi
167114983201Sdp}
167214983201Sdp
1673cdf0c1d5Smjnelsonfunction get_file_mode
1674cdf0c1d5Smjnelson{
1675cdf0c1d5Smjnelson	$PERL -e '
1676cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1677cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1678cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1679cdf0c1d5Smjnelson			exit 0;
1680cdf0c1d5Smjnelson		} else {
1681cdf0c1d5Smjnelson			exit 1;
1682cdf0c1d5Smjnelson		}
1683cdf0c1d5Smjnelson	    ' $1
1684cdf0c1d5Smjnelson}
1685cdf0c1d5Smjnelson
1686cdf0c1d5Smjnelsonfunction build_old_new_teamware
1687cdf0c1d5Smjnelson{
1688cdf0c1d5Smjnelson	typeset olddir="$1"
1689cdf0c1d5Smjnelson	typeset newdir="$2"
1690cdf0c1d5Smjnelson
1691cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1692cdf0c1d5Smjnelson	# get a readonly copy.
1693cdf0c1d5Smjnelson
1694cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1695cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1696cdf0c1d5Smjnelson	fi
1697cdf0c1d5Smjnelson
1698cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1699cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1700cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1701cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1702cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1703cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1704cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1705cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1706cdf0c1d5Smjnelson	# permissions that would result after check in.
1707cdf0c1d5Smjnelson
1708cdf0c1d5Smjnelson	#
1709cdf0c1d5Smjnelson	# Snag new version of file.
1710cdf0c1d5Smjnelson	#
1711cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1712cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1713cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1714cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1715cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1716cdf0c1d5Smjnelson	fi
1717cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1718cdf0c1d5Smjnelson
1719cdf0c1d5Smjnelson	#
1720cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1721cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1722cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1723cdf0c1d5Smjnelson	#
1724cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1725cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1726cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1727cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1728cdf0c1d5Smjnelson		# the old file.
1729cdf0c1d5Smjnelson
1730cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1731cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1732cdf0c1d5Smjnelson	else
1733cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1734cdf0c1d5Smjnelson			real_parent=$PWS
1735cdf0c1d5Smjnelson		else
1736cdf0c1d5Smjnelson			real_parent=$RWS
1737cdf0c1d5Smjnelson		fi
1738cdf0c1d5Smjnelson
1739cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1740cdf0c1d5Smjnelson
1741cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1742cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1743cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1744cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1745cdf0c1d5Smjnelson			else
1746cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1747cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1748cdf0c1d5Smjnelson			fi
1749cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1750cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1751cdf0c1d5Smjnelson		fi
1752cdf0c1d5Smjnelson	fi
1753cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1754cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1755cdf0c1d5Smjnelson	fi
1756cdf0c1d5Smjnelson}
1757cdf0c1d5Smjnelson
1758cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1759cdf0c1d5Smjnelson{
1760cdf0c1d5Smjnelson	typeset olddir="$1"
1761cdf0c1d5Smjnelson	typeset newdir="$2"
1762cdf0c1d5Smjnelson	typeset old_mode=
1763cdf0c1d5Smjnelson	typeset new_mode=
1764cdf0c1d5Smjnelson	typeset file
1765cdf0c1d5Smjnelson
1766cdf0c1d5Smjnelson	#
1767cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1768cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1769cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1770cdf0c1d5Smjnelson	#
1771cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1772cdf0c1d5Smjnelson		file="$PF"
1773cdf0c1d5Smjnelson	else
1774cdf0c1d5Smjnelson		file="$PDIR/$PF"
1775cdf0c1d5Smjnelson	fi
1776cdf0c1d5Smjnelson	file=`echo $file | sed 's#/#\\\/#g'`
1777cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1778cdf0c1d5Smjnelson	old_mode=`sed -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1779cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1780cdf0c1d5Smjnelson
1781cdf0c1d5Smjnelson	#
1782cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1783cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1784cdf0c1d5Smjnelson	#
1785cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1786cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1787cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1788cdf0c1d5Smjnelson			new_mode=755
1789cdf0c1d5Smjnelson		else
1790cdf0c1d5Smjnelson			new_mode=644
1791cdf0c1d5Smjnelson		fi
1792cdf0c1d5Smjnelson	fi
1793cdf0c1d5Smjnelson
1794cdf0c1d5Smjnelson	#
1795cdf0c1d5Smjnelson	# new version of the file.
1796cdf0c1d5Smjnelson	#
1797cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1798cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1799cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1800cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1801cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1802cdf0c1d5Smjnelson		else
1803cdf0c1d5Smjnelson			# should never happen
1804cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1805cdf0c1d5Smjnelson		fi
1806cdf0c1d5Smjnelson	fi
1807cdf0c1d5Smjnelson
1808cdf0c1d5Smjnelson	#
1809cdf0c1d5Smjnelson	# parent's version of the file
1810cdf0c1d5Smjnelson	#
1811cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1812cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1813cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1814cdf0c1d5Smjnelson	#
1815cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1816cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1817cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1818cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1819cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1820cdf0c1d5Smjnelson
182102d26c39SVladimir Kotal		if (( $? != 0 )); then
1822cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1823cdf0c1d5Smjnelson		else
1824cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1825cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1826cdf0c1d5Smjnelson			else
1827cdf0c1d5Smjnelson				# should never happen
1828cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1829cdf0c1d5Smjnelson			fi
1830cdf0c1d5Smjnelson		fi
1831cdf0c1d5Smjnelson	fi
1832cdf0c1d5Smjnelson}
1833cdf0c1d5Smjnelson
1834cdf0c1d5Smjnelsonfunction build_old_new_subversion
1835cdf0c1d5Smjnelson{
1836cdf0c1d5Smjnelson	typeset olddir="$1"
1837cdf0c1d5Smjnelson	typeset newdir="$2"
1838cdf0c1d5Smjnelson
1839cdf0c1d5Smjnelson	# Snag new version of file.
1840cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1841cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1842cdf0c1d5Smjnelson
1843cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1844cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1845cdf0c1d5Smjnelson	else
1846cdf0c1d5Smjnelson		# Get the parent's version of the file.
1847cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
1848cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
1849cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
1850cdf0c1d5Smjnelson		fi
1851cdf0c1d5Smjnelson	fi
1852cdf0c1d5Smjnelson}
1853cdf0c1d5Smjnelson
1854cdf0c1d5Smjnelsonfunction build_old_new_unknown
1855cdf0c1d5Smjnelson{
1856cdf0c1d5Smjnelson	typeset olddir="$1"
1857cdf0c1d5Smjnelson	typeset newdir="$2"
1858cdf0c1d5Smjnelson
1859cdf0c1d5Smjnelson	#
1860cdf0c1d5Smjnelson	# Snag new version of file.
1861cdf0c1d5Smjnelson	#
1862cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1863cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1864cdf0c1d5Smjnelson
1865cdf0c1d5Smjnelson	#
1866cdf0c1d5Smjnelson	# Snag the parent's version of the file.
1867cdf0c1d5Smjnelson	#
1868cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
1869cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1870cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1871cdf0c1d5Smjnelson	fi
1872cdf0c1d5Smjnelson}
1873cdf0c1d5Smjnelson
1874cdf0c1d5Smjnelsonfunction build_old_new
1875cdf0c1d5Smjnelson{
1876cdf0c1d5Smjnelson	typeset WDIR=$1
1877cdf0c1d5Smjnelson	typeset PWS=$2
1878cdf0c1d5Smjnelson	typeset PDIR=$3
1879cdf0c1d5Smjnelson	typeset PF=$4
1880cdf0c1d5Smjnelson	typeset CWS=$5
1881cdf0c1d5Smjnelson	typeset DIR=$6
1882cdf0c1d5Smjnelson	typeset F=$7
1883cdf0c1d5Smjnelson
1884cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
1885cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
1886cdf0c1d5Smjnelson
1887cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
1888cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
1889cdf0c1d5Smjnelson
1890cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1891cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
1892cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
1893cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
1894cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
1895cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
1896cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
1897cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
1898cdf0c1d5Smjnelson	fi
1899cdf0c1d5Smjnelson
1900cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
1901cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
1902cdf0c1d5Smjnelson		return 1
1903cdf0c1d5Smjnelson	fi
1904cdf0c1d5Smjnelson	return 0
1905cdf0c1d5Smjnelson}
1906cdf0c1d5Smjnelson
1907cdf0c1d5Smjnelson
1908daaffb31Sdp#
1909daaffb31Sdp# Usage message.
1910daaffb31Sdp#
1911daaffb31Sdpfunction usage
1912daaffb31Sdp{
1913daaffb31Sdp	print 'Usage:\twebrev [common-options]
1914daaffb31Sdp	webrev [common-options] ( <file> | - )
1915daaffb31Sdp	webrev [common-options] -w <wx file>
1916daaffb31Sdp
1917daaffb31SdpOptions:
1918*ba44d8a2SVladimir Kotal	-D: delete remote webrev
1919daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
1920*ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
1921*ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
1922daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
1923daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
192402d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
192502d26c39SVladimir Kotal	-U: upload the webrev to remote destination
1926daaffb31Sdp	-w <wxfile>: Use specified wx active file.
1927daaffb31Sdp
1928daaffb31SdpEnvironment:
1929daaffb31Sdp	WDIR: Control the output directory.
1930daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
1931daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
1932*ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
1933daaffb31Sdp
1934cdf0c1d5SmjnelsonSCM Specific Options:
1935cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
1936cdf0c1d5Smjnelson
1937daaffb31SdpSCM Environment:
1938cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
1939cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
1940daaffb31Sdp'
1941daaffb31Sdp
1942daaffb31Sdp	exit 2
1943daaffb31Sdp}
1944daaffb31Sdp
1945daaffb31Sdp#
1946daaffb31Sdp#
1947daaffb31Sdp# Main program starts here
1948daaffb31Sdp#
1949daaffb31Sdp#
1950daaffb31Sdp
1951daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1952daaffb31Sdp
1953daaffb31Sdpset +o noclobber
1954daaffb31Sdp
1955cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
1956cdf0c1d5Smjnelson
195714983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
195814983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
1959cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
1960cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
196114983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
196214983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
196314983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
196402d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
1965cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
1966cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
1967cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
1968cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
196902d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
197002d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
197102d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
197202d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
1973*ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
1974cdf0c1d5Smjnelson
1975*ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
1976*ba44d8a2SVladimir KotalTRASH_DIR=".trash"
1977*ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
197814983201Sdp
197914983201Sdpif [[ ! -x $PERL ]]; then
198014983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
198114983201Sdp	exit 1
1982daaffb31Sdpfi
198314983201Sdp
1984cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
1985cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
1986cdf0c1d5Smjnelson	exit 1
1987cdf0c1d5Smjnelsonfi
1988cdf0c1d5Smjnelson
198914983201Sdp#
199014983201Sdp# These aren't fatal, but we want to note them to the user.
199114983201Sdp# We don't warn on the absence of 'wx' until later when we've
199214983201Sdp# determined that we actually need to try to invoke it.
199314983201Sdp#
199414983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
199514983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
199614983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
1997daaffb31Sdp
1998daaffb31Sdp# Declare global total counters.
1999daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2000daaffb31Sdp
2001*ba44d8a2SVladimir Kotal# default remote host for upload/delete
2002*ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2003*ba44d8a2SVladimir Kotal
2004*ba44d8a2SVladimir KotalDflag=
200514983201Sdpflist_mode=
200614983201Sdpflist_file=
2007daaffb31Sdpiflag=
200802d26c39SVladimir Kotallflag=
200902d26c39SVladimir KotalNflag=
201002d26c39SVladimir Kotalnflag=
201102d26c39SVladimir KotalOflag=
2012daaffb31Sdpoflag=
2013daaffb31Sdppflag=
201402d26c39SVladimir Kotaltflag=
201502d26c39SVladimir Kotaluflag=
201602d26c39SVladimir KotalUflag=
2017daaffb31Sdpwflag=
201802d26c39SVladimir Kotalremote_target=
2019*ba44d8a2SVladimir Kotal
2020*ba44d8a2SVladimir Kotal#
2021*ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2022*ba44d8a2SVladimir Kotal# 	with usr/src/tools/onbld/hgext/cdm.py
2023*ba44d8a2SVladimir Kotal#
2024*ba44d8a2SVladimir Kotalwhile getopts "i:o:p:lwONnt:UD" opt
2025daaffb31Sdpdo
2026daaffb31Sdp	case $opt in
2027*ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2028*ba44d8a2SVladimir Kotal
2029daaffb31Sdp	i)	iflag=1
2030daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2031daaffb31Sdp
2032daaffb31Sdp	#
2033daaffb31Sdp	# If -l has been specified, we need to abort further options
2034daaffb31Sdp	# processing, because subsequent arguments are going to be
2035daaffb31Sdp	# arguments to 'putback -n'.
2036daaffb31Sdp	#
2037daaffb31Sdp	l)	lflag=1
2038daaffb31Sdp		break;;
2039daaffb31Sdp
204002d26c39SVladimir Kotal	N)	Nflag=1;;
204102d26c39SVladimir Kotal
204202d26c39SVladimir Kotal	n)	nflag=1;;
2043daaffb31Sdp
2044daaffb31Sdp	O)	Oflag=1;;
2045daaffb31Sdp
204602d26c39SVladimir Kotal	o)	oflag=1
204702d26c39SVladimir Kotal		WDIR=$OPTARG;;
204802d26c39SVladimir Kotal
204902d26c39SVladimir Kotal	p)	pflag=1
205002d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
205102d26c39SVladimir Kotal
205202d26c39SVladimir Kotal	t)	tflag=1
205302d26c39SVladimir Kotal		remote_target=$OPTARG;;
205402d26c39SVladimir Kotal
205502d26c39SVladimir Kotal	U)	Uflag=1;;
205602d26c39SVladimir Kotal
205702d26c39SVladimir Kotal	w)	wflag=1;;
20583df69ef3SDarren Moffat
2059daaffb31Sdp	?)	usage;;
2060daaffb31Sdp	esac
2061daaffb31Sdpdone
2062daaffb31Sdp
2063daaffb31SdpFLIST=/tmp/$$.flist
2064daaffb31Sdp
2065daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2066daaffb31Sdp	usage
2067daaffb31Sdpfi
2068daaffb31Sdp
206902d26c39SVladimir Kotal# more sanity checking
207002d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2071*ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2072*ba44d8a2SVladimir Kotal	    "without -U"
207302d26c39SVladimir Kotal	exit 1
207402d26c39SVladimir Kotalfi
207502d26c39SVladimir Kotal
2076*ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2077*ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
207802d26c39SVladimir Kotal	exit 1
207902d26c39SVladimir Kotalfi
208002d26c39SVladimir Kotal
2081daaffb31Sdp#
2082daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2083daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2084daaffb31Sdp#
2085daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2086daaffb31Sdp	parent_webrev="$codemgr_parent"
2087daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2088daaffb31Sdpfi
2089daaffb31Sdp
2090daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2091daaffb31Sdp	shift $(($OPTIND - 1))
2092daaffb31Sdp
2093daaffb31Sdp	if [[ $1 == "-" ]]; then
2094daaffb31Sdp		cat > $FLIST
209514983201Sdp		flist_mode="stdin"
209614983201Sdp		flist_done=1
209714983201Sdp		shift
2098daaffb31Sdp	elif [[ -n $1 ]]; then
209914983201Sdp		if [[ ! -r $1 ]]; then
2100daaffb31Sdp			print -u2 "$1: no such file or not readable"
2101daaffb31Sdp			usage
2102daaffb31Sdp		fi
2103daaffb31Sdp		cat $1 > $FLIST
210414983201Sdp		flist_mode="file"
210514983201Sdp		flist_file=$1
210614983201Sdp		flist_done=1
210714983201Sdp		shift
2108daaffb31Sdp	else
210914983201Sdp		flist_mode="auto"
2110daaffb31Sdp	fi
2111daaffb31Sdpfi
2112daaffb31Sdp
2113daaffb31Sdp#
2114daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2115daaffb31Sdp# is in use.
2116daaffb31Sdp#
2117cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
2118cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2119cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2120cdf0c1d5Smjnelson	;;
2121cdf0c1d5Smjnelsonunknown)
2122cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2123cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2124cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
21257c478bd9Sstevel@tonic-gate		exit 1
21267c478bd9Sstevel@tonic-gate	fi
2127cdf0c1d5Smjnelson	;;
2128cdf0c1d5Smjnelson*)
2129cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2130cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2131cdf0c1d5Smjnelson		exit 1
2132cdf0c1d5Smjnelson	fi
2133cdf0c1d5Smjnelson	;;
2134cdf0c1d5Smjnelsonesac
21357c478bd9Sstevel@tonic-gate
2136daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2137daaffb31Sdp
2138daaffb31Sdpif [[ -n $lflag ]]; then
2139daaffb31Sdp	#
2140daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2141daaffb31Sdp	# then generate the file list by extracting file names from a
2142daaffb31Sdp	# putback -n.
2143daaffb31Sdp	#
2144daaffb31Sdp	shift $(($OPTIND - 1))
2145cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2146daaffb31Sdp		flist_from_teamware "$*"
2147cdf0c1d5Smjnelson	else
2148cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2149cdf0c1d5Smjnelson		exit 1
2150cdf0c1d5Smjnelson	fi
2151daaffb31Sdp	flist_done=1
2152daaffb31Sdp	shift $#
2153daaffb31Sdpelif [[ -n $wflag ]]; then
2154daaffb31Sdp	#
2155daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2156daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2157daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2158daaffb31Sdp	# in building the index.html file.
2159daaffb31Sdp	#
2160daaffb31Sdp	shift $(($OPTIND - 1))
2161daaffb31Sdp	wxfile=$1
2162daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2163daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2164daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2165daaffb31Sdp		fi
2166daaffb31Sdp	fi
2167daaffb31Sdp
2168daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2169daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2170daaffb31Sdp
2171cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2172cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2173cdf0c1d5Smjnelson		usage
2174cdf0c1d5Smjnelson	fi
2175cdf0c1d5Smjnelson
2176daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2177daaffb31Sdp	flist_from_wx $wxfile
2178daaffb31Sdp	flist_done=1
2179daaffb31Sdp	if [[ -n "$*" ]]; then
2180daaffb31Sdp		shift
2181daaffb31Sdp	fi
218214983201Sdpelif [[ $flist_mode == "stdin" ]]; then
218314983201Sdp	print -u2 " File list from: standard input"
218414983201Sdpelif [[ $flist_mode == "file" ]]; then
218514983201Sdp	print -u2 " File list from: $flist_file"
2186daaffb31Sdpfi
2187daaffb31Sdp
2188daaffb31Sdpif [[ $# -gt 0 ]]; then
218914983201Sdp	print -u2 "WARNING: unused arguments: $*"
2190daaffb31Sdpfi
2191daaffb31Sdp
2192daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
2193daaffb31Sdp	#
2194daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
2195daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
2196daaffb31Sdp	#
2197daaffb31Sdp	#      1) on the command line (only for the parent)
2198daaffb31Sdp	#      2) in the user environment
2199daaffb31Sdp	#      3) in the flist
2200daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
2201daaffb31Sdp	#
2202daaffb31Sdp
2203daaffb31Sdp	#
2204daaffb31Sdp	# Here is case (2): the user environment
2205daaffb31Sdp	#
2206daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2207daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2208daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
22097c478bd9Sstevel@tonic-gate		exit 1
22107c478bd9Sstevel@tonic-gate	fi
22117c478bd9Sstevel@tonic-gate
2212daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2213daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2214daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2215daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
22167c478bd9Sstevel@tonic-gate		exit 1
22177c478bd9Sstevel@tonic-gate	fi
22187c478bd9Sstevel@tonic-gate
2219daaffb31Sdp	#
2220daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2221daaffb31Sdp	# list, then see if we can get it by probing for wx.
2222daaffb31Sdp	#
222314983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
222414983201Sdp		if [[ ! -x $WX ]]; then
222514983201Sdp			print -u2 "WARNING: wx not found!"
2226daaffb31Sdp		fi
22277c478bd9Sstevel@tonic-gate
2228daaffb31Sdp		#
2229daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2230daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2231daaffb31Sdp		# hang asking us to initialize our wx information.
2232daaffb31Sdp		#
223314983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2234daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2235daaffb31Sdp			$WX list -w > $FLIST
2236daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2237daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2238daaffb31Sdp			print -u2 "done"
2239daaffb31Sdp			flist_done=1
2240daaffb31Sdp		fi
2241daaffb31Sdp	fi
2242daaffb31Sdp
2243daaffb31Sdp	#
2244daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2245daaffb31Sdp	# from the command line), eval it to extract environment variables from
2246daaffb31Sdp	# it: This is step (3).
2247daaffb31Sdp	#
2248daaffb31Sdp	env_from_flist
2249daaffb31Sdp
2250daaffb31Sdp	#
2251daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2252daaffb31Sdp	# it from teamware.
2253daaffb31Sdp	#
2254daaffb31Sdp	if [[ -z $flist_done ]]; then
2255daaffb31Sdp		flist_from_teamware
2256daaffb31Sdp		env_from_flist
2257daaffb31Sdp	fi
2258daaffb31Sdp
2259daaffb31Sdp	#
2260daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2261daaffb31Sdp	# from workspace.
2262daaffb31Sdp	#
2263cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2264daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2265daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2266daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2267daaffb31Sdp		exit 1
2268daaffb31Sdp	fi
2269daaffb31Sdp
2270daaffb31Sdp	#
2271cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2272cdf0c1d5Smjnelson	# webrev title.
2273cdf0c1d5Smjnelson	#
2274cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2275cdf0c1d5Smjnelson
2276cdf0c1d5Smjnelson	#
2277daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2278daaffb31Sdp	#
2279daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2280daaffb31Sdp	CWS=$codemgr_ws
2281daaffb31Sdp	PWS=$codemgr_parent
2282cdf0c1d5Smjnelson
2283cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2284cdf0c1d5Smjnelson
2285cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2286cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2287cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2288cdf0c1d5Smjnelson
2289cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2290cdf0c1d5Smjnelson
2291cdf0c1d5Smjnelson	#
2292cdf0c1d5Smjnelson	# Parent can either be specified with -p
2293cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2294cdf0c1d5Smjnelson	# or taken from hg's default path.
2295cdf0c1d5Smjnelson	#
2296cdf0c1d5Smjnelson
2297cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2298cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2299cdf0c1d5Smjnelson	fi
2300cdf0c1d5Smjnelson
2301cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2302cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2303cdf0c1d5Smjnelson	fi
2304cdf0c1d5Smjnelson
2305cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2306cdf0c1d5Smjnelson	CWS=$codemgr_ws
2307cdf0c1d5Smjnelson	PWS=$codemgr_parent
2308cdf0c1d5Smjnelson
2309cdf0c1d5Smjnelson	#
2310cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2311cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2312cdf0c1d5Smjnelson	#
2313cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2314cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2315cdf0c1d5Smjnelson	else
2316cdf0c1d5Smjnelson		real_parent=$PWS
2317cdf0c1d5Smjnelson	fi
2318cdf0c1d5Smjnelson
2319cdf0c1d5Smjnelson	#
2320cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2321cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2322cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2323cdf0c1d5Smjnelson	# files mentioned in the flist.
2324cdf0c1d5Smjnelson	#
2325cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2326cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2327cdf0c1d5Smjnelson		flist_done=1
2328cdf0c1d5Smjnelson	fi
2329cdf0c1d5Smjnelson
2330cdf0c1d5Smjnelson	#
2331cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2332cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2333cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2334cdf0c1d5Smjnelson	# in the user-specified flist.
2335cdf0c1d5Smjnelson	#
2336cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2337cdf0c1d5Smjnelson		env_from_flist
2338cdf0c1d5Smjnelson	fi
2339cdf0c1d5Smjnelson
2340cdf0c1d5Smjnelson	#
2341cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2342cdf0c1d5Smjnelson	#
2343cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2344cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2345cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2346cdf0c1d5Smjnelson		print " Done."
2347cdf0c1d5Smjnelson	fi
2348cdf0c1d5Smjnelson
2349cdf0c1d5Smjnelson	#
2350cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2351cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2352cdf0c1d5Smjnelson	# if we don't have one.
2353cdf0c1d5Smjnelson	#
2354cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
235502d26c39SVladimir Kotal		eval `sed -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2356cdf0c1d5Smjnelson	fi
2357cdf0c1d5Smjnelson
2358cdf0c1d5Smjnelson	#
2359cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2360cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2361cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2362cdf0c1d5Smjnelson	#
2363cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2364cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
236502d26c39SVladimir Kotal		    eval `sed -e "s/#.*$//" | $GREP HG_PARENT=`
2366cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2367cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2368cdf0c1d5Smjnelson		exit 1
2369cdf0c1d5Smjnelson	fi
2370cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2371cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2372cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2373cdf0c1d5Smjnelson	else
2374cdf0c1d5Smjnelson		svn info | while read line; do
2375cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2376cdf0c1d5Smjnelson				url=${line#URL: }
2377cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2378cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2379cdf0c1d5Smjnelson			fi
2380cdf0c1d5Smjnelson		done
2381cdf0c1d5Smjnelson
2382cdf0c1d5Smjnelson		rel=${url#$repo}
2383cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2384cdf0c1d5Smjnelson	fi
2385cdf0c1d5Smjnelson
2386cdf0c1d5Smjnelson	#
2387cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2388cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2389cdf0c1d5Smjnelson	#
2390cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2391cdf0c1d5Smjnelson
2392cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2393cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2394cdf0c1d5Smjnelson	fi
2395cdf0c1d5Smjnelsonelse
2396cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2397cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2398cdf0c1d5Smjnelson    else
2399cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2400cdf0c1d5Smjnelson    fi
2401cdf0c1d5Smjnelson
2402cdf0c1d5Smjnelson    env_from_flist
2403cdf0c1d5Smjnelson
2404cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2405cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2406cdf0c1d5Smjnelson	exit 1
2407cdf0c1d5Smjnelson    fi
2408cdf0c1d5Smjnelson
2409cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2410cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2411cdf0c1d5Smjnelson	exit 1
2412cdf0c1d5Smjnelson    fi
2413cdf0c1d5Smjnelson
2414cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2415cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2416daaffb31Sdpfi
2417daaffb31Sdp
2418daaffb31Sdp#
2419daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2420daaffb31Sdp# webrev-info file in the workspace directory.
2421daaffb31Sdp#
2422daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2423daaffb31Sdp	iflag=1
2424daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2425daaffb31Sdpfi
2426daaffb31Sdp
2427daaffb31Sdpif [[ -n $iflag ]]; then
2428daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2429daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2430daaffb31Sdp		    "not readable."
2431daaffb31Sdp		exit 1
2432daaffb31Sdp	else
2433daaffb31Sdp		#
2434daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2435daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2436daaffb31Sdp		#
2437daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2438daaffb31Sdp	fi
2439daaffb31Sdpfi
2440daaffb31Sdp
2441daaffb31Sdp#
2442daaffb31Sdp# Output directory.
2443daaffb31Sdp#
2444daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2445daaffb31Sdp
2446daaffb31Sdp#
244702d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
244802d26c39SVladimir Kotal# in the future this could potentially be an option.
2449daaffb31Sdp#
245002d26c39SVladimir Kotalif [[ -n $oflag ]]; then
245102d26c39SVladimir Kotal	WNAME=${WDIR##*/}
245202d26c39SVladimir Kotalelse
2453daaffb31Sdp	WNAME=${CWS##*/}
245402d26c39SVladimir Kotalfi
245502d26c39SVladimir Kotal
2456*ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2457*ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2458*ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2459*ba44d8a2SVladimir Kotal	# the default values.
2460*ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2461*ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2462*ba44d8a2SVladimir Kotal	else
2463*ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2464*ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2465*ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2466*ba44d8a2SVladimir Kotal		# local webrev directory name.
2467*ba44d8a2SVladimir Kotal		if [[ -z ${remote_target##*:} ]]; then
2468*ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2469*ba44d8a2SVladimir Kotal				dst=${remote_target}${WNAME}
2470*ba44d8a2SVladimir Kotal			else
2471*ba44d8a2SVladimir Kotal				dst=${remote_target}:${WNAME}
2472*ba44d8a2SVladimir Kotal			fi
2473*ba44d8a2SVladimir Kotal		fi
2474*ba44d8a2SVladimir Kotal	fi
2475*ba44d8a2SVladimir Kotalfi
2476*ba44d8a2SVladimir Kotal
2477*ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2478*ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2479*ba44d8a2SVladimir Kotal	delete_webrev 1
2480*ba44d8a2SVladimir Kotal	exit $?
2481*ba44d8a2SVladimir Kotalfi
2482*ba44d8a2SVladimir Kotal
2483*ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2484*ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2485*ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2486*ba44d8a2SVladimir Kotal		delete_webrev 1
2487*ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2488*ba44d8a2SVladimir Kotal	fi
2489*ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
249002d26c39SVladimir Kotal		upload_webrev
249102d26c39SVladimir Kotal		exit $?
249202d26c39SVladimir Kotal	fi
2493*ba44d8a2SVladimir Kotalfi
2494daaffb31Sdp
2495e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
24967c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
24977c478bd9Sstevel@tonic-gatefi
2498daaffb31Sdp
2499daaffb31Sdpif [[ ! -d $WDIR ]]; then
2500daaffb31Sdp	mkdir -p $WDIR
2501*ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
25027c478bd9Sstevel@tonic-gatefi
25037c478bd9Sstevel@tonic-gate
2504daaffb31Sdp#
2505daaffb31Sdp# Summarize what we're going to do.
2506daaffb31Sdp#
2507cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2508cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2509cdf0c1d5Smjnelsonelse
2510daaffb31Sdp	print "      Workspace: $CWS"
2511cdf0c1d5Smjnelsonfi
2512daaffb31Sdpif [[ -n $parent_webrev ]]; then
2513daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2514daaffb31Sdpelse
2515cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2516cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2517cdf0c1d5Smjnelson			| sed -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2518cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2519cdf0c1d5Smjnelson	else
2520daaffb31Sdp		print "Compare against: $PWS"
2521daaffb31Sdp	fi
2522cdf0c1d5Smjnelsonfi
2523daaffb31Sdp
2524daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2525daaffb31Sdpprint "      Output to: $WDIR"
2526daaffb31Sdp
2527daaffb31Sdp#
25287c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2529daaffb31Sdp#
2530daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
25317c478bd9Sstevel@tonic-gate
2532daaffb31Sdp#
2533daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2534daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2535daaffb31Sdp#
2536daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2537daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2538daaffb31Sdp[[ -n "$Oflag" ]] && \
2539daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
25407c478bd9Sstevel@tonic-gate
2541daaffb31Sdp#
2542daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2543daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2544daaffb31Sdp#
2545daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2546daaffb31Sdp#    SACURL.  See sac2url().
2547daaffb31Sdp#
2548daaffb31SdpSACURL='http://sac.eng.sun.com'
2549daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2550e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2551daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
25527c478bd9Sstevel@tonic-gate
2553daaffb31Sdprm -f $WDIR/$WNAME.patch
2554daaffb31Sdprm -f $WDIR/$WNAME.ps
2555daaffb31Sdprm -f $WDIR/$WNAME.pdf
25567c478bd9Sstevel@tonic-gate
2557daaffb31Sdptouch $WDIR/$WNAME.patch
25587c478bd9Sstevel@tonic-gate
2559daaffb31Sdpprint "   Output Files:"
2560daaffb31Sdp
2561daaffb31Sdp#
2562daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2563daaffb31Sdp#
2564daaffb31Sdpsed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2565daaffb31SdpFLIST=/tmp/$$.flist.clean
2566daaffb31Sdp
2567daaffb31Sdp#
2568cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2569cdf0c1d5Smjnelson#
2570cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2571cdf0c1d5Smjnelson	#
2572cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2573cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2574cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2575cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2576cdf0c1d5Smjnelson	#    keep only the old name.
2577cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2578cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2579cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2580cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2581cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2582cdf0c1d5Smjnelson	#
2583cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2584cdf0c1d5Smjnelson	sed '
2585cdf0c1d5Smjnelson		s#^[^ ]* ##
2586cdf0c1d5Smjnelson		s#/#\\\/#g
2587cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2588cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2589cdf0c1d5Smjnelson
2590cdf0c1d5Smjnelson	#
2591cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2592cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2593cdf0c1d5Smjnelson	#
2594cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2595cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2596cdf0c1d5Smjnelson	    sed -n -f $SEDFILE > $HG_PARENT_MANIFEST
2597cdf0c1d5Smjnelsonfi
2598cdf0c1d5Smjnelson
2599cdf0c1d5Smjnelson#
2600daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2601daaffb31Sdp#
2602daaffb31Sdpcat $FLIST | while read LINE
26037c478bd9Sstevel@tonic-gatedo
26047c478bd9Sstevel@tonic-gate	set - $LINE
26057c478bd9Sstevel@tonic-gate	P=$1
26067c478bd9Sstevel@tonic-gate
2607daaffb31Sdp	#
2608daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2609daaffb31Sdp	# file that has been modified or created in the child.  A file
2610daaffb31Sdp	# that is renamed in the child workspace has two names on the
2611daaffb31Sdp	# line: new name followed by the old name.
2612daaffb31Sdp	#
2613daaffb31Sdp	oldname=""
2614daaffb31Sdp	oldpath=""
2615daaffb31Sdp	rename=
2616daaffb31Sdp	if [[ $# -eq 2 ]]; then
26177c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2618daaffb31Sdp		oldname=" (was $PP)"
2619daaffb31Sdp		oldpath="$PP"
2620daaffb31Sdp		rename=1
26217c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2622daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
26237c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
26247c478bd9Sstevel@tonic-gate		fi
26257c478bd9Sstevel@tonic-gate
26267c478bd9Sstevel@tonic-gate		PF=${PP##*/}
26277c478bd9Sstevel@tonic-gate
26287c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2629daaffb31Sdp	        if [[ $DIR == $P ]]; then
26307c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
26317c478bd9Sstevel@tonic-gate		fi
26327c478bd9Sstevel@tonic-gate
26337c478bd9Sstevel@tonic-gate		F=${P##*/}
2634daaffb31Sdp
26357c478bd9Sstevel@tonic-gate        else
26367c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2637daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
26387c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
26397c478bd9Sstevel@tonic-gate		fi
26407c478bd9Sstevel@tonic-gate
26417c478bd9Sstevel@tonic-gate		F=${P##*/}
26427c478bd9Sstevel@tonic-gate
26437c478bd9Sstevel@tonic-gate		PP=$P
26447c478bd9Sstevel@tonic-gate		PDIR=$DIR
26457c478bd9Sstevel@tonic-gate		PF=$F
26467c478bd9Sstevel@tonic-gate	fi
26477c478bd9Sstevel@tonic-gate
2648daaffb31Sdp	COMM=`getcomments html $P $PP`
26497c478bd9Sstevel@tonic-gate
2650daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
26517c478bd9Sstevel@tonic-gate
26527c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
26537c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
26547c478bd9Sstevel@tonic-gate
2655daaffb31Sdp	#
2656daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2657daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2658e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2659daaffb31Sdp	#
2660e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2661daaffb31Sdp		pclosed=${P##usr/closed/}
2662e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2663e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2664daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2665daaffb31Sdp			    "mode review"
2666daaffb31Sdp			continue
2667daaffb31Sdp		fi
2668daaffb31Sdp	fi
2669daaffb31Sdp
2670daaffb31Sdp	#
2671cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2672daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2673daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2674daaffb31Sdp	#
2675daaffb31Sdp
2676cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
26777c478bd9Sstevel@tonic-gate	    continue
26787c478bd9Sstevel@tonic-gate
2679cdf0c1d5Smjnelson	#
2680cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2681cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2682cdf0c1d5Smjnelson	# consistent environment.
2683cdf0c1d5Smjnelson	#
2684cdf0c1d5Smjnelson	OWD=$PWD
2685daaffb31Sdp	cd $WDIR/raw_files
2686daaffb31Sdp	ofile=old/$PDIR/$PF
2687daaffb31Sdp	nfile=new/$DIR/$F
26887c478bd9Sstevel@tonic-gate
2689daaffb31Sdp	mv_but_nodiff=
2690daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2691daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2692daaffb31Sdp		mv_but_nodiff=1
2693daaffb31Sdp	fi
2694daaffb31Sdp
2695daaffb31Sdp	#
2696daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2697daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2698daaffb31Sdp	#
2699daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2700daaffb31Sdp	#	  diff and an 'add' diff
2701daaffb31Sdp	#	- new files and deleted files must be handled specially
2702daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2703daaffb31Sdp	#	  (and hence renames) as of this writing.
2704daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2705daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2706daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2707daaffb31Sdp	#         transformations:
2708daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2709daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2710daaffb31Sdp	#
2711daaffb31Sdp	cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2712daaffb31Sdp	cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2713daaffb31Sdp
2714daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2715daaffb31Sdp	if [[ -z $rename ]]; then
2716e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2717daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2718daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2719e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2720daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2721daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2722daaffb31Sdp		else
2723daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2724daaffb31Sdp		fi
2725daaffb31Sdp	else
2726daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2727daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2728daaffb31Sdp
2729daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2730daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2731daaffb31Sdp
2732daaffb31Sdp	fi
2733daaffb31Sdp
2734daaffb31Sdp	#
2735daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2736daaffb31Sdp	# whole wad.
2737daaffb31Sdp	#
2738daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2739daaffb31Sdp
2740daaffb31Sdp	print " patch\c"
2741daaffb31Sdp
2742daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2743daaffb31Sdp
2744daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2745daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2746daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
27477c478bd9Sstevel@tonic-gate		print " cdiffs\c"
27487c478bd9Sstevel@tonic-gate
2749daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2750daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2751daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2752daaffb31Sdp
27537c478bd9Sstevel@tonic-gate		print " udiffs\c"
27547c478bd9Sstevel@tonic-gate
27557c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2756daaffb31Sdp			$WDIFF -c "$COMM" \
2757daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2758daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2759daaffb31Sdp			if [[ $? -eq 0 ]]; then
27607c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2761daaffb31Sdp			else
2762daaffb31Sdp				print " wdiffs[fail]\c"
2763daaffb31Sdp			fi
27647c478bd9Sstevel@tonic-gate		fi
27657c478bd9Sstevel@tonic-gate
2766daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2767daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
27687c478bd9Sstevel@tonic-gate		print " sdiffs\c"
27697c478bd9Sstevel@tonic-gate
27707c478bd9Sstevel@tonic-gate		print " frames\c"
27717c478bd9Sstevel@tonic-gate
27727c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
27737c478bd9Sstevel@tonic-gate
2774daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2775daaffb31Sdp
2776daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2777daaffb31Sdp		# renamed file: may also have differences
2778daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2779daaffb31Sdp	elif [[ -f $nfile ]]; then
27807c478bd9Sstevel@tonic-gate		# new file: count added lines
2781daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2782daaffb31Sdp	elif [[ -f $ofile ]]; then
27837c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2784daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
27857c478bd9Sstevel@tonic-gate	fi
27867c478bd9Sstevel@tonic-gate
2787daaffb31Sdp	#
2788daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
2789daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
2790daaffb31Sdp	# tree-killing to print out the contents of deleted files).
2791daaffb31Sdp	#
2792daaffb31Sdp	if [[ -f $nfile ]]; then
2793daaffb31Sdp		ocr=$ofile
2794daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
2795daaffb31Sdp
2796daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
2797daaffb31Sdp			textcomm=`getcomments text $P $PP`
279814983201Sdp			if [[ -x $CODEREVIEW ]]; then
279914983201Sdp				$CODEREVIEW -y "$textcomm" \
280014983201Sdp				    -e $ocr $nfile \
280114983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
280214983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
2803daaffb31Sdp				if [[ $? -eq 0 ]]; then
2804daaffb31Sdp					print " ps\c"
2805daaffb31Sdp				else
2806daaffb31Sdp					print " ps[fail]\c"
2807daaffb31Sdp				fi
2808daaffb31Sdp			fi
2809daaffb31Sdp		fi
281014983201Sdp	fi
2811daaffb31Sdp
2812cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
2813cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
28147c478bd9Sstevel@tonic-gate		print " old\c"
28157c478bd9Sstevel@tonic-gate	fi
28167c478bd9Sstevel@tonic-gate
2817daaffb31Sdp	if [[ -f $nfile ]]; then
2818daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
28197c478bd9Sstevel@tonic-gate		print " new\c"
28207c478bd9Sstevel@tonic-gate	fi
28217c478bd9Sstevel@tonic-gate
2822cdf0c1d5Smjnelson	cd $OWD
2823cdf0c1d5Smjnelson
2824daaffb31Sdp	print
28257c478bd9Sstevel@tonic-gatedone
28267c478bd9Sstevel@tonic-gate
2827daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
28287c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
2829daaffb31Sdp
283014983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
283114983201Sdp	print " Generating PDF: Skipped: no output available"
283214983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
283314983201Sdp	print " Generating PDF: \c"
283414983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
2835daaffb31Sdp	print "Done."
283614983201Sdpelse
283714983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
283814983201Sdpfi
28397c478bd9Sstevel@tonic-gate
2840e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
2841e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
2842e0e0293aSjmcp
2843e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
2844*ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
2845e0e0293aSjmcpfi
2846e0e0293aSjmcp
28477c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
28487c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
28497c478bd9Sstevel@tonic-gate
28507c478bd9Sstevel@tonic-gatecd $CWS
28517c478bd9Sstevel@tonic-gate
28527c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
2853daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
28547c478bd9Sstevel@tonic-gate
2855daaffb31Sdpprint "     index.html: \c"
28567c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
28577c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
28587c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
28597c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
28607c478bd9Sstevel@tonic-gate
2861daaffb31Sdpprint "$HTML<head>$STDHEAD"
2862daaffb31Sdpprint "<title>$WNAME</title>"
2863daaffb31Sdpprint "</head>"
2864daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
2865daaffb31Sdpprint "<div class=\"summary\">"
2866daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
28677c478bd9Sstevel@tonic-gate
2868daaffb31Sdpprint "<table>"
28697c478bd9Sstevel@tonic-gate
2870daaffb31Sdp#
2871cdf0c1d5Smjnelson# Get the preparer's name:
2872daaffb31Sdp#
2873cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
2874cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
2875cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
2876cdf0c1d5Smjnelson#
2877cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
2878cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
2879cdf0c1d5Smjnelson#
2880cdf0c1d5Smjnelsonpreparer=
2881cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
2882cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
2883cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
2884cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
2885cdf0c1d5Smjnelson	fi
2886cdf0c1d5Smjnelsonfi
2887cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
2888cdf0c1d5Smjnelson	preparer=$(
2889cdf0c1d5Smjnelson	    $PERL -e '
2890cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
2891cdf0c1d5Smjnelson	        if ($login) {
2892cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
2893cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
2894cdf0c1d5Smjnelson	        } else {
2895cdf0c1d5Smjnelson	            printf "(unknown)\n";
2896cdf0c1d5Smjnelson	        }
2897cdf0c1d5Smjnelson	')
2898daaffb31Sdpfi
2899daaffb31Sdp
2900cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
2901cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
2902cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2903cdf0c1d5Smjnelson	print "(at $CWS_REV)"
2904cdf0c1d5Smjnelsonfi
2905cdf0c1d5Smjnelsonprint "</td></tr>"
2906daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
2907daaffb31Sdpif [[ -n $parent_webrev ]]; then
2908daaffb31Sdp	print "webrev at $parent_webrev"
2909daaffb31Sdpelse
2910daaffb31Sdp	print "$PWS"
2911cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
2912cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
2913cdf0c1d5Smjnelson	fi
2914daaffb31Sdpfi
2915daaffb31Sdpprint "</td></tr>"
2916daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
2917daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
2918daaffb31Sdpprint "</td></tr>"
2919daaffb31Sdp
2920daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
2921daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
2922daaffb31Sdp	print "<a href=\"$WNAME.patch\">$WNAME.patch</a></td></tr>"
2923daaffb31Sdpfi
2924daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
2925daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
2926daaffb31Sdp	print "<a href=\"$WNAME.pdf\">$WNAME.pdf</a></td></tr>"
2927daaffb31Sdpfi
2928daaffb31Sdp
2929daaffb31Sdpif [[ -n "$iflag" ]]; then
2930daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
2931daaffb31Sdp	cat /tmp/$$.include
2932daaffb31Sdp	print "</div></td></tr>"
2933daaffb31Sdpfi
2934daaffb31Sdpprint "</table>"
2935daaffb31Sdpprint "</div>"
2936daaffb31Sdp
2937daaffb31Sdp#
2938daaffb31Sdp# Second pass through the files: generate the rest of the index file
2939daaffb31Sdp#
2940daaffb31Sdpcat $FLIST | while read LINE
29417c478bd9Sstevel@tonic-gatedo
29427c478bd9Sstevel@tonic-gate	set - $LINE
29437c478bd9Sstevel@tonic-gate	P=$1
29447c478bd9Sstevel@tonic-gate
2945daaffb31Sdp	if [[ $# == 2 ]]; then
29467c478bd9Sstevel@tonic-gate		PP=$2
2947cdf0c1d5Smjnelson		oldname="$PP"
29487c478bd9Sstevel@tonic-gate	else
29497c478bd9Sstevel@tonic-gate		PP=$P
2950daaffb31Sdp		oldname=""
2951daaffb31Sdp	fi
2952daaffb31Sdp
2953cdf0c1d5Smjnelson	mv_but_nodiff=
2954cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
2955cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
2956cdf0c1d5Smjnelson		mv_but_nodiff=1
2957cdf0c1d5Smjnelson	fi
2958cdf0c1d5Smjnelson
2959daaffb31Sdp	DIR=${P%/*}
2960daaffb31Sdp	if [[ $DIR == $P ]]; then
2961daaffb31Sdp		DIR="."   # File at root of workspace
29627c478bd9Sstevel@tonic-gate	fi
29637c478bd9Sstevel@tonic-gate
29647c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
29657c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
29667c478bd9Sstevel@tonic-gate	# appear twice in the file list
29677c478bd9Sstevel@tonic-gate
29687c478bd9Sstevel@tonic-gate	F=$WDIR/$P
29697c478bd9Sstevel@tonic-gate
2970daaffb31Sdp	print "<p>"
29717c478bd9Sstevel@tonic-gate
29727c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
29737c478bd9Sstevel@tonic-gate
2974daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
2975daaffb31Sdp		print "<a href=\"$P.cdiff.html\">Cdiffs</a>"
2976daaffb31Sdp		print "<a href=\"$P.udiff.html\">Udiffs</a>"
29777c478bd9Sstevel@tonic-gate
2978daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
2979daaffb31Sdp			print "<a href=\"$P.wdiff.html\">Wdiffs</a>"
29807c478bd9Sstevel@tonic-gate		fi
29817c478bd9Sstevel@tonic-gate
2982daaffb31Sdp		print "<a href=\"$P.sdiff.html\">Sdiffs</a>"
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate		print "<a href=\"$P.frames.html\">Frames</a>"
29857c478bd9Sstevel@tonic-gate	else
2986daaffb31Sdp		print " ------ ------ ------"
29877c478bd9Sstevel@tonic-gate
2988daaffb31Sdp		if [[ -x $WDIFF ]]; then
29897c478bd9Sstevel@tonic-gate			print " ------"
29907c478bd9Sstevel@tonic-gate		fi
2991daaffb31Sdp
2992daaffb31Sdp		print " ------"
29937c478bd9Sstevel@tonic-gate	fi
29947c478bd9Sstevel@tonic-gate
29957c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
29967c478bd9Sstevel@tonic-gate
2997daaffb31Sdp	if [[ -f $F-.html ]]; then
2998daaffb31Sdp		print "<a href=\"$P-.html\">Old</a>"
29997c478bd9Sstevel@tonic-gate	else
3000daaffb31Sdp		print " ---"
30017c478bd9Sstevel@tonic-gate	fi
30027c478bd9Sstevel@tonic-gate
30037c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
30047c478bd9Sstevel@tonic-gate
3005daaffb31Sdp	if [[ -f $F.html ]]; then
3006daaffb31Sdp		print "<a href=\"$P.html\">New</a>"
30077c478bd9Sstevel@tonic-gate	else
3008daaffb31Sdp		print " ---"
30097c478bd9Sstevel@tonic-gate	fi
30107c478bd9Sstevel@tonic-gate
3011daaffb31Sdp	if [[ -f $F.patch ]]; then
3012daaffb31Sdp		print "<a href=\"$P.patch\">Patch</a>"
3013daaffb31Sdp	else
3014daaffb31Sdp		print " -----"
3015daaffb31Sdp	fi
3016daaffb31Sdp
3017daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3018daaffb31Sdp		print "<a href=\"raw_files/new/$P\">Raw</a>"
3019daaffb31Sdp	else
3020daaffb31Sdp		print " ---"
3021daaffb31Sdp	fi
3022daaffb31Sdp
3023cdf0c1d5Smjnelson	print "<b>$P</b>"
3024cdf0c1d5Smjnelson
3025cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3026cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
3027cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3028cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
3029cdf0c1d5Smjnelson		else
3030cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
3031cdf0c1d5Smjnelson		fi
3032cdf0c1d5Smjnelson	fi
3033cdf0c1d5Smjnelson
3034cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3035cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3036cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3037cdf0c1d5Smjnelson	fi
3038daaffb31Sdp
3039daaffb31Sdp	#
3040e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3041daaffb31Sdp	#
3042daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3043e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3044e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3045daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3046daaffb31Sdp			    "this review</i>"
3047daaffb31Sdp		fi
3048daaffb31Sdp	fi
3049daaffb31Sdp
3050daaffb31Sdp	print "</p>"
30517c478bd9Sstevel@tonic-gate	# Insert delta comments
30527c478bd9Sstevel@tonic-gate
3053daaffb31Sdp	print "<blockquote><pre>"
3054daaffb31Sdp	getcomments html $P $PP
3055daaffb31Sdp	print "</pre>"
30567c478bd9Sstevel@tonic-gate
30577c478bd9Sstevel@tonic-gate	# Add additional comments comment
30587c478bd9Sstevel@tonic-gate
3059daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
30607c478bd9Sstevel@tonic-gate
30617c478bd9Sstevel@tonic-gate	# Add count of changes.
30627c478bd9Sstevel@tonic-gate
3063daaffb31Sdp	if [[ -f $F.count ]]; then
30647c478bd9Sstevel@tonic-gate	    cat $F.count
30657c478bd9Sstevel@tonic-gate	    rm $F.count
30667c478bd9Sstevel@tonic-gate	fi
3067cdf0c1d5Smjnelson
3068cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3069cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3070cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3071cdf0c1d5Smjnelson
3072cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3073cdf0c1d5Smjnelson		# 1) New executable files
3074cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3075cdf0c1d5Smjnelson		# 3) Existing executable files
3076cdf0c1d5Smjnelson
3077cdf0c1d5Smjnelson		old_mode=
3078cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3079cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3080cdf0c1d5Smjnelson		fi
3081cdf0c1d5Smjnelson
3082cdf0c1d5Smjnelson		new_mode=
3083cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3084cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3085cdf0c1d5Smjnelson		fi
3086cdf0c1d5Smjnelson
3087cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3088cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3089cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3090cdf0c1d5Smjnelson			print "</span>"
3091cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3092cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3093cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3094cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3095cdf0c1d5Smjnelson			print "</span>"
3096cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3097cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3098cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3099cdf0c1d5Smjnelson			print "</span>"
3100cdf0c1d5Smjnelson		fi
3101cdf0c1d5Smjnelson	fi
3102cdf0c1d5Smjnelson
3103daaffb31Sdp	print "</blockquote>"
31047c478bd9Sstevel@tonic-gatedone
31057c478bd9Sstevel@tonic-gate
3106daaffb31Sdpprint
3107daaffb31Sdpprint
3108cac38512Smjnelsonprint "<hr></hr>"
3109daaffb31Sdpprint "<p style=\"font-size: small\">"
31109a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3111daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3112daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3113e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3114daaffb31Sdpprint "</body>"
3115daaffb31Sdpprint "</html>"
31167c478bd9Sstevel@tonic-gate
31177c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
31187c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
31197c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
31207c478bd9Sstevel@tonic-gate
3121daaffb31Sdpprint "Done."
312202d26c39SVladimir Kotal
3123*ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3124*ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3125*ba44d8a2SVladimir Kotal	delete_webrev 1
3126*ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3127*ba44d8a2SVladimir Kotalfi
3128*ba44d8a2SVladimir Kotal
312902d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
313002d26c39SVladimir Kotal	upload_webrev
313102d26c39SVladimir Kotal	exit $?
313202d26c39SVladimir Kotalfi
3133