xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 371d72dab1d0327bfe09b175ad38db564e3e245a)
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#
24*371d72daSLubomir Sedlacik# Copyright 2009 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.
145ba44d8a2SVladimir 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
153ba44d8a2SVladimir 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.
168ba44d8a2SVladimir Kotalfunction ssh_upload
16902d26c39SVladimir Kotal{
17002d26c39SVladimir Kotal	if (( $# != 1 )); then
171ba44d8a2SVladimir 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%%:*}
177ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
17802d26c39SVladimir Kotal
179ba44d8a2SVladimir Kotal	# if the deletion was explicitly requested there is no need
180ba44d8a2SVladimir Kotal	# to perform it again
181ba44d8a2SVladimir 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
184ba44d8a2SVladimir 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
191ba44d8a2SVladimir 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
216ba44d8a2SVladimir 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#
230ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
231ba44d8a2SVladimir Kotal# on failure.
232ba44d8a2SVladimir Kotal#
233ba44d8a2SVladimir Kotalfunction delete_webrev
234ba44d8a2SVladimir Kotal{
235ba44d8a2SVladimir Kotal	if (( $# != 1 )); then
236ba44d8a2SVladimir Kotal		print "delete_webrev: wrong usage"
237ba44d8a2SVladimir Kotal		return 1
238ba44d8a2SVladimir Kotal	fi
239ba44d8a2SVladimir Kotal
240ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
241ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
242ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
243ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
244ba44d8a2SVladimir Kotal	integer -r check=$1
245ba44d8a2SVladimir Kotal	typeset dir_rm
246ba44d8a2SVladimir Kotal
247ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
248ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
249ba44d8a2SVladimir Kotal		return 1
250ba44d8a2SVladimir Kotal	fi
251ba44d8a2SVladimir Kotal
252ba44d8a2SVladimir Kotal	# Strip the ending slash.
253ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
254ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
255ba44d8a2SVladimir Kotal	else
256ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
257ba44d8a2SVladimir Kotal	fi
258ba44d8a2SVladimir Kotal
259ba44d8a2SVladimir Kotal	print "Removing remote: \c"
260ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
261ba44d8a2SVladimir Kotal		print "empty directory for removal"
262ba44d8a2SVladimir Kotal		return 1
263ba44d8a2SVladimir Kotal	fi
264ba44d8a2SVladimir Kotal
265ba44d8a2SVladimir Kotal	# Prepare batch file.
266ba44d8a2SVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXX )
267ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
268ba44d8a2SVladimir Kotal		print "Cannot create temporary file"
269ba44d8a2SVladimir Kotal		return 1
270ba44d8a2SVladimir Kotal	fi
271ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
272ba44d8a2SVladimir Kotal
273ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
274ba44d8a2SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>/dev/null 1>&2
275ba44d8a2SVladimir Kotal	integer -r ret=$?
276ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
277ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
278ba44d8a2SVladimir Kotal		print "Failed"
279ba44d8a2SVladimir Kotal		return $ret
280ba44d8a2SVladimir Kotal	fi
281ba44d8a2SVladimir Kotal	print "Done."
282ba44d8a2SVladimir Kotal
283ba44d8a2SVladimir Kotal	return 0
284ba44d8a2SVladimir Kotal}
285ba44d8a2SVladimir Kotal
286ba44d8a2SVladimir Kotal#
28702d26c39SVladimir Kotal# Upload webrev to remote site
28802d26c39SVladimir Kotal#
289ba44d8a2SVladimir 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
303ba44d8a2SVladimir 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
325ba44d8a2SVladimir Kotal		rsync_upload ${remote_target}
32602d26c39SVladimir Kotal		if (( $? != 0 )); then
32702d26c39SVladimir Kotal			echo "rsync upload failed, falling back to SSH"
328ba44d8a2SVladimir 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#
337*371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
338*371d72daSLubomir Sedlacik#
339*371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
340*371d72daSLubomir Sedlacik#
341*371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
342*371d72daSLubomir Sedlacik#
343*371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
344*371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
345*371d72daSLubomir Sedlacik# a path delimiter.
346*371d72daSLubomir Sedlacik#
347*371d72daSLubomir Sedlacikfunction url_encode
348*371d72daSLubomir Sedlacik{
349*371d72daSLubomir Sedlacik	sed -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
350*371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
351*371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
352*371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
353*371d72daSLubomir Sedlacik	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|\'|%27|g" \
354*371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
355*371d72daSLubomir Sedlacik}
356*371d72daSLubomir Sedlacik
357*371d72daSLubomir Sedlacik#
358daaffb31Sdp# input_cmd | html_quote | output_cmd
359daaffb31Sdp# or
360daaffb31Sdp# html_quote filename | output_cmd
3617c478bd9Sstevel@tonic-gate#
3627c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
3637c478bd9Sstevel@tonic-gate#
3647c478bd9Sstevel@tonic-gatehtml_quote()
3657c478bd9Sstevel@tonic-gate{
3667c478bd9Sstevel@tonic-gate	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
3677c478bd9Sstevel@tonic-gate}
3687c478bd9Sstevel@tonic-gate
369daaffb31Sdp#
370daaffb31Sdp# input_cmd | bug2url | output_cmd
371daaffb31Sdp#
372daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
373daaffb31Sdp#
374daaffb31Sdpbug2url()
3757c478bd9Sstevel@tonic-gate{
376daaffb31Sdp	sed -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
377daaffb31Sdp}
378daaffb31Sdp
3797c478bd9Sstevel@tonic-gate#
380daaffb31Sdp# input_cmd | sac2url | output_cmd
3817c478bd9Sstevel@tonic-gate#
382daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
383daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
384daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
385daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
3867c478bd9Sstevel@tonic-gate#
387daaffb31Sdpsac2url()
388daaffb31Sdp{
389e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
3900a30ef2cSstevel	    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'
391daaffb31Sdp	else
392daaffb31Sdp	    sed -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
393daaffb31Sdp	fi
394daaffb31Sdp}
395daaffb31Sdp
3967c478bd9Sstevel@tonic-gate#
397daaffb31Sdp# strip_unchanged <infile> | output_cmd
3987c478bd9Sstevel@tonic-gate#
399daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
400daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
4017c478bd9Sstevel@tonic-gate#
402daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
403daaffb31Sdp# identical lines are retained before and after the changed lines to
404daaffb31Sdp# provide some context.  The number of these lines is controlled by the
405cdf0c1d5Smjnelson# variable C in the $AWK script below.
406daaffb31Sdp#
407daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
408daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
409daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
410daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
411daaffb31Sdp#
412daaffb31Sdpstrip_unchanged()
413daaffb31Sdp{
414cdf0c1d5Smjnelson	$AWK '
415daaffb31Sdp	BEGIN	{ C = c = 20 }
416cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
417daaffb31Sdp		if (c > C) {
418daaffb31Sdp			c -= C
419daaffb31Sdp			inx = 0
420daaffb31Sdp			if (c > C) {
421cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
422daaffb31Sdp				inx = c % C
423daaffb31Sdp				c = C
424daaffb31Sdp			}
425daaffb31Sdp
426daaffb31Sdp			for (i = 0; i < c; i++)
427daaffb31Sdp				print ln[(inx + i) % C]
428daaffb31Sdp		}
429daaffb31Sdp		c = 0;
430daaffb31Sdp		print
431daaffb31Sdp		next
432daaffb31Sdp	}
433daaffb31Sdp	{	if (c >= C) {
434daaffb31Sdp			ln[c % C] = $0
435daaffb31Sdp			c++;
436daaffb31Sdp			next;
437daaffb31Sdp		}
438daaffb31Sdp		c++;
439daaffb31Sdp		print
440daaffb31Sdp	}
441cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
442daaffb31Sdp
443daaffb31Sdp	' $1
444daaffb31Sdp}
445daaffb31Sdp
446daaffb31Sdp#
447daaffb31Sdp# sdiff_to_html
448daaffb31Sdp#
449daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
450daaffb31Sdp# processes the diff output to present the files as an HTML document with
451daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
452daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
453daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
454daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
455daaffb31Sdp# e.g.
456daaffb31Sdp#
457daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
458daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
459daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
460daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
461daaffb31Sdp#          1234567</a> my bugid' > <file>.html
462daaffb31Sdp#
463daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
464daaffb31Sdp# in the webrev tree.
465daaffb31Sdp#
466daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
467daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
468daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
469daaffb31Sdp# the editing codes, e.g.
4707c478bd9Sstevel@tonic-gate#
4717c478bd9Sstevel@tonic-gate#      8c8
4727c478bd9Sstevel@tonic-gate#      57a61
4737c478bd9Sstevel@tonic-gate#      63c66,76
4747c478bd9Sstevel@tonic-gate#      68,93d80
4757c478bd9Sstevel@tonic-gate#      106d90
4767c478bd9Sstevel@tonic-gate#      108,110d91
4777c478bd9Sstevel@tonic-gate#
478daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
479daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
480daaffb31Sdp#  into something like this:
4817c478bd9Sstevel@tonic-gate#
4827c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
4837c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
484daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
4857c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
4867c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
4877c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
4887c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
4897c478bd9Sstevel@tonic-gate#        :               :
4907c478bd9Sstevel@tonic-gate#
491daaffb31Sdp#  This script is then run on the original source file to generate the
492daaffb31Sdp#  HTML that corresponds to the source file.
4937c478bd9Sstevel@tonic-gate#
494daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
495daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
496daaffb31Sdp#  notice that the changes are color-coded:
4977c478bd9Sstevel@tonic-gate#
4987c478bd9Sstevel@tonic-gate#   black     - unchanged lines
4997c478bd9Sstevel@tonic-gate#   blue      - changed lines
5007c478bd9Sstevel@tonic-gate#   bold blue - new lines
5017c478bd9Sstevel@tonic-gate#   brown     - deleted lines
5027c478bd9Sstevel@tonic-gate#
503daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
504daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
505daaffb31Sdp#  Teamware's filemerge tool.
506daaffb31Sdp#
507daaffb31Sdpsdiff_to_html()
508daaffb31Sdp{
5097c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
5107c478bd9Sstevel@tonic-gate
511daaffb31Sdp	TNAME=$3
512daaffb31Sdp	TPATH=$4
513daaffb31Sdp	COMMENT=$5
514daaffb31Sdp
5157c478bd9Sstevel@tonic-gate	#
5167c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
5177c478bd9Sstevel@tonic-gate	#
518cdf0c1d5Smjnelson	$AWK '
5197c478bd9Sstevel@tonic-gate	BEGIN	{
5207c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
521daaffb31Sdp		printf "function removed() "
522daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
523daaffb31Sdp		printf "function changed() "
524daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
525daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
5267c478bd9Sstevel@tonic-gate}
5277c478bd9Sstevel@tonic-gate	/^</	{next}
5287c478bd9Sstevel@tonic-gate	/^>/	{next}
5297c478bd9Sstevel@tonic-gate	/^---/	{next}
530daaffb31Sdp
5317c478bd9Sstevel@tonic-gate	{
5327c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
5337c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
5347c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
5357c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
5367c478bd9Sstevel@tonic-gate			if (n == 1)
5377c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
5387c478bd9Sstevel@tonic-gate			else
5397c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
5407c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
5417c478bd9Sstevel@tonic-gate			next
5427c478bd9Sstevel@tonic-gate		}
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
5457c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
5467c478bd9Sstevel@tonic-gate		s = r[1];
5477c478bd9Sstevel@tonic-gate		if (n == 1)
5487c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
5497c478bd9Sstevel@tonic-gate		else {
5507c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
5517c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
5527c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
5537c478bd9Sstevel@tonic-gate		}
5547c478bd9Sstevel@tonic-gate		next
5557c478bd9Sstevel@tonic-gate	}
5567c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
5577c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5587c478bd9Sstevel@tonic-gate		n1 = r[1]
5597c478bd9Sstevel@tonic-gate		n2 = r[2]
5607c478bd9Sstevel@tonic-gate		if (n == 1)
561daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
5627c478bd9Sstevel@tonic-gate		else
563daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
5647c478bd9Sstevel@tonic-gate		next
5657c478bd9Sstevel@tonic-gate	}
5667c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
5677c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
5687c478bd9Sstevel@tonic-gate		n1 = r[1]
5697c478bd9Sstevel@tonic-gate		n2 = r[2]
5707c478bd9Sstevel@tonic-gate		final = n2
5717c478bd9Sstevel@tonic-gate		d1 = 0
5727c478bd9Sstevel@tonic-gate		if (n == 1)
573daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
5747c478bd9Sstevel@tonic-gate		else {
5757c478bd9Sstevel@tonic-gate			d1 = n2 - n1
576daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
5777c478bd9Sstevel@tonic-gate		}
5787c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
5797c478bd9Sstevel@tonic-gate		n1 = r[1]
5807c478bd9Sstevel@tonic-gate		n2 = r[2]
5817c478bd9Sstevel@tonic-gate		if (m > 1) {
5827c478bd9Sstevel@tonic-gate			d2  = n2 - n1
5837c478bd9Sstevel@tonic-gate			if (d2 > d1) {
5847c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
5857c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
5867c478bd9Sstevel@tonic-gate			}
5877c478bd9Sstevel@tonic-gate		}
5887c478bd9Sstevel@tonic-gate		printf "next}\n" ;
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate		next
5917c478bd9Sstevel@tonic-gate	}
5927c478bd9Sstevel@tonic-gate	}
5937c478bd9Sstevel@tonic-gate
594daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
595daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate	#
5987c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
5997c478bd9Sstevel@tonic-gate	#
600cdf0c1d5Smjnelson	$AWK '
6017c478bd9Sstevel@tonic-gate	BEGIN	{
6027c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
603daaffb31Sdp		printf "function new() "
604daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
605daaffb31Sdp		printf "function changed() "
606daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
607daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6087c478bd9Sstevel@tonic-gate	}
609daaffb31Sdp
6107c478bd9Sstevel@tonic-gate	/^</	{next}
6117c478bd9Sstevel@tonic-gate	/^>/	{next}
6127c478bd9Sstevel@tonic-gate	/^---/	{next}
613daaffb31Sdp
6147c478bd9Sstevel@tonic-gate	{
6157c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6167c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
6177c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
6187c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
6197c478bd9Sstevel@tonic-gate			if (n == 1)
6207c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6217c478bd9Sstevel@tonic-gate			else
6227c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6237c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6247c478bd9Sstevel@tonic-gate			next
6257c478bd9Sstevel@tonic-gate		}
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
6287c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
6297c478bd9Sstevel@tonic-gate		s = r[1];
6307c478bd9Sstevel@tonic-gate		if (n == 1)
6317c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6327c478bd9Sstevel@tonic-gate		else {
6337c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6347c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6357c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6367c478bd9Sstevel@tonic-gate		}
6377c478bd9Sstevel@tonic-gate		next
6387c478bd9Sstevel@tonic-gate	}
6397c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6407c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6417c478bd9Sstevel@tonic-gate		n1 = r[1]
6427c478bd9Sstevel@tonic-gate		n2 = r[2]
6437c478bd9Sstevel@tonic-gate		if (n == 1)
644daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
6457c478bd9Sstevel@tonic-gate		else
646daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
6477c478bd9Sstevel@tonic-gate		next
6487c478bd9Sstevel@tonic-gate	}
6497c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
6507c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6517c478bd9Sstevel@tonic-gate		n1 = r[1]
6527c478bd9Sstevel@tonic-gate		n2 = r[2]
6537c478bd9Sstevel@tonic-gate		final = n2
6547c478bd9Sstevel@tonic-gate		d2 = 0;
6557c478bd9Sstevel@tonic-gate		if (n == 1) {
6567c478bd9Sstevel@tonic-gate			final = n1
657daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
6587c478bd9Sstevel@tonic-gate		} else {
6597c478bd9Sstevel@tonic-gate			d2 = n2 - n1
660daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
6617c478bd9Sstevel@tonic-gate		}
6627c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
6637c478bd9Sstevel@tonic-gate		n1 = r[1]
6647c478bd9Sstevel@tonic-gate		n2 = r[2]
6657c478bd9Sstevel@tonic-gate		if (m > 1) {
6667c478bd9Sstevel@tonic-gate			d1  = n2 - n1
6677c478bd9Sstevel@tonic-gate			if (d1 > d2) {
6687c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
6697c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
6707c478bd9Sstevel@tonic-gate			}
6717c478bd9Sstevel@tonic-gate		}
6727c478bd9Sstevel@tonic-gate		printf "next}\n" ;
6737c478bd9Sstevel@tonic-gate		next
6747c478bd9Sstevel@tonic-gate	}
6757c478bd9Sstevel@tonic-gate	}
676daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
6777c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
6787c478bd9Sstevel@tonic-gate
679daaffb31Sdp	#
680cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
681daaffb31Sdp	#
682cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
6837c478bd9Sstevel@tonic-gate
684cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
6857c478bd9Sstevel@tonic-gate
686daaffb31Sdp	#
687daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
688daaffb31Sdp	#
689daaffb31Sdp	print "$HTML<head>$STDHEAD"
690cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
691daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
692daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
693daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
694daaffb31Sdp	print "<table><tr valign=\"top\">"
695daaffb31Sdp	print "<td><pre>"
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
6987c478bd9Sstevel@tonic-gate
699daaffb31Sdp	print "</pre></td><td><pre>"
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
7027c478bd9Sstevel@tonic-gate
703daaffb31Sdp	print "</pre></td>"
704daaffb31Sdp	print "</tr></table>"
705daaffb31Sdp	print "</body></html>"
7067c478bd9Sstevel@tonic-gate
707daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
708daaffb31Sdp	    "$COMMENT"
7097c478bd9Sstevel@tonic-gate}
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate
712daaffb31Sdp#
713daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
714daaffb31Sdp#
715daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
716daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
717daaffb31Sdp# and then emit the main frame.  Content is placed into:
718daaffb31Sdp#
719daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
720daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
721daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
722daaffb31Sdp#
723daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
724daaffb31Sdp#
7257c478bd9Sstevel@tonic-gatefunction framed_sdiff
7267c478bd9Sstevel@tonic-gate{
7277c478bd9Sstevel@tonic-gate	typeset TNAME=$1
728daaffb31Sdp	typeset TPATH=$2
729daaffb31Sdp	typeset lhsfile=$3
730daaffb31Sdp	typeset rhsfile=$4
731daaffb31Sdp	typeset comments=$5
7327c478bd9Sstevel@tonic-gate	typeset RTOP
733daaffb31Sdp
7347c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
735daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
736daaffb31Sdp
737daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
738daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
739daaffb31Sdp
740daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
741cac38512Smjnelson	    <script type="text/javascript" src="$RTOP/ancnav.js"></script>
7427c478bd9Sstevel@tonic-gate	    </head>
743daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
744cac38512Smjnelson	    <a name="0"></a>
745cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
746daaffb31Sdp	EOF
747daaffb31Sdp
748daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
749daaffb31Sdp
750daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
751daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
752daaffb31Sdp
753daaffb31Sdp	close='</body></html>'
754daaffb31Sdp
755daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
756daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
757daaffb31Sdp
758daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
759daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
760daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
761daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
762daaffb31Sdp	  <frameset rows="*,60">
763daaffb31Sdp	    <frameset cols="50%,50%">
764cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
765cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
766daaffb31Sdp	    </frameset>
767daaffb31Sdp	  <frame src="$RTOP/ancnav.html" scrolling="no" marginwidth="0"
768cac38512Smjnelson	   marginheight="0" name="nav"></frame>
769daaffb31Sdp	  <noframes>
770daaffb31Sdp            <body id="SUNWwebrev">
771daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
7727c478bd9Sstevel@tonic-gate	      and has the feature enabled.
773daaffb31Sdp            </body>
774daaffb31Sdp	  </noframes>
775daaffb31Sdp	  </frameset>
7767c478bd9Sstevel@tonic-gate	</html>
7777c478bd9Sstevel@tonic-gate	EOF
7787c478bd9Sstevel@tonic-gate}
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate
781daaffb31Sdp#
782daaffb31Sdp# fix_postscript
783daaffb31Sdp#
784daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
785daaffb31Sdp# 	- removing all extraneous headers/trailers
786daaffb31Sdp#	- making the page numbers right
787daaffb31Sdp#	- removing pages devoid of contents which confuse some
788daaffb31Sdp#	  postscript readers.
789daaffb31Sdp#
790daaffb31Sdp# From Casper.
791daaffb31Sdp#
792daaffb31Sdpfunction fix_postscript
7937c478bd9Sstevel@tonic-gate{
794daaffb31Sdp	infile=$1
7957c478bd9Sstevel@tonic-gate
796daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
7977c478bd9Sstevel@tonic-gate
798daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
799daaffb31Sdp	print "%%Orientation: Landscape\n";
8007c478bd9Sstevel@tonic-gate
801daaffb31Sdp	$pno = 0;
802daaffb31Sdp	$doprint = 1;
803daaffb31Sdp
804daaffb31Sdp	$page = "";
805daaffb31Sdp
806daaffb31Sdp	while (<>) {
807daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
808daaffb31Sdp
809daaffb31Sdp		if (/^%%Page:/) {
810daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
811daaffb31Sdp				# Header or single page containing text
812daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
813daaffb31Sdp				print $page;
814daaffb31Sdp				$pno++;
815daaffb31Sdp			} else {
816daaffb31Sdp				# Empty page, skip it.
8177c478bd9Sstevel@tonic-gate			}
818daaffb31Sdp			$page = "";
819daaffb31Sdp			$doprint = 1;
8207c478bd9Sstevel@tonic-gate			next;
8217c478bd9Sstevel@tonic-gate		}
8227c478bd9Sstevel@tonic-gate
823daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
824daaffb31Sdp		# %%Page of the next
825daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
826daaffb31Sdp		$page .= $_ if ($doprint);
8277c478bd9Sstevel@tonic-gate	}
8287c478bd9Sstevel@tonic-gate
829daaffb31Sdp	if ($page =~ /\)S/) {
830daaffb31Sdp		print "%%Page: ? $pno\n";
831daaffb31Sdp		print $page;
832daaffb31Sdp	} else {
833daaffb31Sdp		$pno--;
834daaffb31Sdp	}
835daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
836daaffb31SdpEOF
837daaffb31Sdp
83814983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
839daaffb31Sdp}
840daaffb31Sdp
841daaffb31Sdp
842daaffb31Sdp#
843daaffb31Sdp# input_cmd | insert_anchors | output_cmd
844daaffb31Sdp#
8457c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
846daaffb31Sdp# anchors.  These are used to drive the frames version of the
8477c478bd9Sstevel@tonic-gate# sdiffs output.
8487c478bd9Sstevel@tonic-gate#
8497c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
8507c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
8517c478bd9Sstevel@tonic-gate#
852daaffb31Sdp# The script detects changed lines as any line that has a "<span
853daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
854daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
8557c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
8567c478bd9Sstevel@tonic-gate# deleted.
8577c478bd9Sstevel@tonic-gate#
858daaffb31Sdpfunction insert_anchors
859daaffb31Sdp{
860cdf0c1d5Smjnelson	$AWK '
8617c478bd9Sstevel@tonic-gate	function ia() {
862daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
8637c478bd9Sstevel@tonic-gate	}
864daaffb31Sdp
8657c478bd9Sstevel@tonic-gate	BEGIN {
866daaffb31Sdp		anc=1;
8677c478bd9Sstevel@tonic-gate		inblock=1;
868daaffb31Sdp		printf "<pre>\n";
8697c478bd9Sstevel@tonic-gate	}
870daaffb31Sdp	NF == 0 || /^<span class=/ {
8717c478bd9Sstevel@tonic-gate		if (inblock == 0) {
8727c478bd9Sstevel@tonic-gate			ia();
8737c478bd9Sstevel@tonic-gate			inblock=1;
8747c478bd9Sstevel@tonic-gate		}
8757c478bd9Sstevel@tonic-gate		print;
8767c478bd9Sstevel@tonic-gate		next;
8777c478bd9Sstevel@tonic-gate	}
8787c478bd9Sstevel@tonic-gate	{
8797c478bd9Sstevel@tonic-gate		inblock=0;
8807c478bd9Sstevel@tonic-gate		print;
8817c478bd9Sstevel@tonic-gate	}
8827c478bd9Sstevel@tonic-gate	END {
8837c478bd9Sstevel@tonic-gate		ia();
884daaffb31Sdp
885daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
886daaffb31Sdp		printf "--- EOF ---</b>"
8877c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
888daaffb31Sdp		printf "</pre>"
889daaffb31Sdp		printf "<form name=\"eof\">";
890cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
891cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
892daaffb31Sdp		printf "</form>";
8937c478bd9Sstevel@tonic-gate	}
8947c478bd9Sstevel@tonic-gate	' $1
8957c478bd9Sstevel@tonic-gate}
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate
898daaffb31Sdp#
899daaffb31Sdp# relative_dir
900daaffb31Sdp#
901daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
902daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
903daaffb31Sdp# this function would print "../../../../".
904daaffb31Sdp#
905daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
906daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
907daaffb31Sdp# is not relocatable.
908daaffb31Sdp#
909daaffb31Sdpfunction relative_dir
9107c478bd9Sstevel@tonic-gate{
911daaffb31Sdp	typeset cur="${1##$2?(/)}"
912daaffb31Sdp	typeset ret=""
913daaffb31Sdp	if [[ $2 == $cur ]]; then   # Should never happen.
914daaffb31Sdp		# Should never happen.
91514983201Sdp		print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
916daaffb31Sdp		print -u2 "to \"$2\".  Check input paths.  Framed webrev "
917daaffb31Sdp		print -u2 "will not be relocatable!"
918daaffb31Sdp		print $2
919daaffb31Sdp		return
920daaffb31Sdp	fi
921daaffb31Sdp
922daaffb31Sdp	while [[ -n ${cur} ]];
9237c478bd9Sstevel@tonic-gate	do
9247c478bd9Sstevel@tonic-gate		cur=${cur%%*(/)*([!/])}
925daaffb31Sdp		if [[ -z $ret ]]; then
926daaffb31Sdp			ret=".."
927daaffb31Sdp		else
9287c478bd9Sstevel@tonic-gate			ret="../$ret"
929daaffb31Sdp		fi
9307c478bd9Sstevel@tonic-gate	done
9317c478bd9Sstevel@tonic-gate	print $ret
9327c478bd9Sstevel@tonic-gate}
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate
935daaffb31Sdp#
936daaffb31Sdp# frame_nav_js
937daaffb31Sdp#
938daaffb31Sdp# Emit javascript for frame navigation
939daaffb31Sdp#
940daaffb31Sdpfunction frame_nav_js
9417c478bd9Sstevel@tonic-gate{
9427c478bd9Sstevel@tonic-gatecat << \EOF
9437c478bd9Sstevel@tonic-gatevar myInt;
9447c478bd9Sstevel@tonic-gatevar scrolling=0;
945daaffb31Sdpvar sfactor = 3;
9467c478bd9Sstevel@tonic-gatevar scount=10;
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gatefunction scrollByPix() {
9497c478bd9Sstevel@tonic-gate	if (scount<=0) {
9507c478bd9Sstevel@tonic-gate		sfactor*=1.2;
9517c478bd9Sstevel@tonic-gate		scount=10;
9527c478bd9Sstevel@tonic-gate	}
9537c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
9547c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
9557c478bd9Sstevel@tonic-gate	scount--;
9567c478bd9Sstevel@tonic-gate}
9577c478bd9Sstevel@tonic-gate
958daaffb31Sdpfunction scrollToAnc(num) {
959daaffb31Sdp
960daaffb31Sdp	// Update the value of the anchor in the form which we use as
961daaffb31Sdp	// storage for this value.  setAncValue() will take care of
962daaffb31Sdp	// correcting for overflow and underflow of the value and return
963daaffb31Sdp	// us the new value.
964daaffb31Sdp	num = setAncValue(num);
965daaffb31Sdp
966daaffb31Sdp	// Set location and scroll back a little to expose previous
967daaffb31Sdp	// lines.
968daaffb31Sdp	//
969daaffb31Sdp	// Note that this could be improved: it is possible although
970daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
971daaffb31Sdp	// scroll to that location directly.
972daaffb31Sdp	//
9737c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
9747c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
975daaffb31Sdp
9767c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
9777c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
9787c478bd9Sstevel@tonic-gate}
9797c478bd9Sstevel@tonic-gate
980daaffb31Sdpfunction getAncValue()
981daaffb31Sdp{
982daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
983daaffb31Sdp}
984daaffb31Sdp
985daaffb31Sdpfunction setAncValue(val)
986daaffb31Sdp{
987daaffb31Sdp	if (val <= 0) {
988daaffb31Sdp		val = 0;
989daaffb31Sdp		parent.nav.document.diff.real.value = val;
990daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
991daaffb31Sdp		return (val);
992daaffb31Sdp	}
993daaffb31Sdp
994daaffb31Sdp	//
995daaffb31Sdp	// The way we compute the max anchor value is to stash it
996daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
997daaffb31Sdp	// on each side, so we pluck from the left.
998daaffb31Sdp	//
999daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1000daaffb31Sdp	if (val < maxval) {
1001daaffb31Sdp		parent.nav.document.diff.real.value = val;
1002daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1003daaffb31Sdp		return (val);
1004daaffb31Sdp	}
1005daaffb31Sdp
1006daaffb31Sdp	// this must be: val >= maxval
1007daaffb31Sdp	val = maxval;
1008daaffb31Sdp	parent.nav.document.diff.real.value = val;
1009daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1010daaffb31Sdp	return (val);
1011daaffb31Sdp}
1012daaffb31Sdp
10137c478bd9Sstevel@tonic-gatefunction stopScroll() {
10147c478bd9Sstevel@tonic-gate	if (scrolling==1) {
10157c478bd9Sstevel@tonic-gate		clearInterval(myInt);
10167c478bd9Sstevel@tonic-gate		scrolling=0;
10177c478bd9Sstevel@tonic-gate	}
10187c478bd9Sstevel@tonic-gate}
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gatefunction startScroll() {
10217c478bd9Sstevel@tonic-gate	stopScroll();
10227c478bd9Sstevel@tonic-gate	scrolling=1;
10237c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
10247c478bd9Sstevel@tonic-gate}
10257c478bd9Sstevel@tonic-gate
10267c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1027daaffb31Sdp
10287c478bd9Sstevel@tonic-gate	switch (b) {
10297c478bd9Sstevel@tonic-gate	    case 1 :
1030daaffb31Sdp		scrollToAnc(-1);
10317c478bd9Sstevel@tonic-gate		break;
10327c478bd9Sstevel@tonic-gate	    case 2 :
1033daaffb31Sdp		scrollToAnc(getAncValue() - 1);
10347c478bd9Sstevel@tonic-gate		break;
10357c478bd9Sstevel@tonic-gate	    case 3 :
10367c478bd9Sstevel@tonic-gate		sfactor=-3;
10377c478bd9Sstevel@tonic-gate		startScroll();
10387c478bd9Sstevel@tonic-gate		break;
10397c478bd9Sstevel@tonic-gate	    case 4 :
10407c478bd9Sstevel@tonic-gate		sfactor=3;
10417c478bd9Sstevel@tonic-gate		startScroll();
10427c478bd9Sstevel@tonic-gate		break;
10437c478bd9Sstevel@tonic-gate	    case 5 :
1044daaffb31Sdp		scrollToAnc(getAncValue() + 1);
10457c478bd9Sstevel@tonic-gate		break;
10467c478bd9Sstevel@tonic-gate	    case 6 :
1047daaffb31Sdp		scrollToAnc(999999);
10487c478bd9Sstevel@tonic-gate		break;
10497c478bd9Sstevel@tonic-gate	}
10507c478bd9Sstevel@tonic-gate}
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
10537c478bd9Sstevel@tonic-gate	stopScroll();
10547c478bd9Sstevel@tonic-gate}
10557c478bd9Sstevel@tonic-gate
1056daaffb31Sdpfunction keypress(ev) {
1057daaffb31Sdp	var keynum;
1058daaffb31Sdp	var keychar;
1059daaffb31Sdp
1060daaffb31Sdp	if (window.event) { // IE
1061daaffb31Sdp		keynum = ev.keyCode;
1062daaffb31Sdp	} else if (ev.which) { // non-IE
1063daaffb31Sdp		keynum = ev.which;
1064daaffb31Sdp	}
1065daaffb31Sdp
1066daaffb31Sdp	keychar = String.fromCharCode(keynum);
1067daaffb31Sdp
1068daaffb31Sdp	if (keychar == "k") {
1069daaffb31Sdp		handlePress(2);
1070daaffb31Sdp		return (0);
1071daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1072daaffb31Sdp		handlePress(5);
1073daaffb31Sdp		return (0);
1074daaffb31Sdp	}
1075daaffb31Sdp	return (1);
1076daaffb31Sdp}
1077daaffb31Sdp
10787c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1079daaffb31Sdp	val = parent.nav.document.diff.display.value;
1080daaffb31Sdp	if (val == "EOF") {
1081daaffb31Sdp		scrollToAnc(999999);
1082daaffb31Sdp		return;
1083daaffb31Sdp	}
1084daaffb31Sdp
1085daaffb31Sdp	if (val == "BOF") {
1086daaffb31Sdp		scrollToAnc(0);
1087daaffb31Sdp		return;
1088daaffb31Sdp	}
1089daaffb31Sdp
1090daaffb31Sdp        i=parseInt(val);
10917c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1092daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
10937c478bd9Sstevel@tonic-gate        } else {
1094daaffb31Sdp                scrollToAnc(i);
10957c478bd9Sstevel@tonic-gate        }
10967c478bd9Sstevel@tonic-gate        return false;
10977c478bd9Sstevel@tonic-gate}
10987c478bd9Sstevel@tonic-gate
1099daaffb31SdpEOF
1100daaffb31Sdp}
1101daaffb31Sdp
1102daaffb31Sdp#
1103daaffb31Sdp# frame_navigation
1104daaffb31Sdp#
1105daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1106daaffb31Sdp#
1107daaffb31Sdpfunction frame_navigation
1108daaffb31Sdp{
1109daaffb31Sdp	print "$HTML<head>$STDHEAD"
1110daaffb31Sdp
1111daaffb31Sdp	cat << \EOF
1112daaffb31Sdp<title>Anchor Navigation</title>
1113daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1114daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1115daaffb31Sdp
1116daaffb31Sdp<style type="text/css">
1117daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1118daaffb31Sdp		    background-color: #eee; text-align: center;
1119daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1120daaffb31Sdp    div.button a { font-weight: bold; color: black }
1121daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1122daaffb31Sdp</style>
1123daaffb31SdpEOF
1124daaffb31Sdp
1125cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1126daaffb31Sdp
1127daaffb31Sdp	cat << \EOF
11287c478bd9Sstevel@tonic-gate</head>
1129daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1130daaffb31Sdp	onkeypress="keypress(event);">
11317c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
11327c478bd9Sstevel@tonic-gate      <center>
1133cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
11347c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
11357c478bd9Sstevel@tonic-gate      </center>
11367c478bd9Sstevel@tonic-gate    </noscript>
11377c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1138daaffb31Sdp	<tr>
1139daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1140daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1141daaffb31Sdp          at right</td>
1142daaffb31Sdp	  <td align="center" valign="top" width="50%">
11437c478bd9Sstevel@tonic-gate	    <div class="button">
1144daaffb31Sdp	      <table border="0" align="center">
1145daaffb31Sdp                  <tr>
1146daaffb31Sdp		    <td>
11477c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
11487c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
11497c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
11507c478bd9Sstevel@tonic-gate			 onClick="return false;"
11517c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1152daaffb31Sdp		    <td>
11537c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
11547c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
11557c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
11567c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1157daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1158daaffb31Sdp		    <td>
11597c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
11607c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
11617c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
11627c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
11637c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
11647c478bd9Sstevel@tonic-gate		    </td></tr>
1165daaffb31Sdp
11667c478bd9Sstevel@tonic-gate		  <tr>
1167daaffb31Sdp		    <td>
11687c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
11697c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
11707c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
11717c478bd9Sstevel@tonic-gate			 onClick="return false;"
11727c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1173daaffb31Sdp		    <td>
11747c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
11757c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
11767c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
11777c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1178daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1179daaffb31Sdp		    <td>
11807c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
11817c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
11827c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
11837c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
11847c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1185daaffb31Sdp		  </tr>
1186daaffb31Sdp              </table>
1187daaffb31Sdp	    </div>
1188daaffb31Sdp	  </td>
11897c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1190daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1191cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1192cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
11937c478bd9Sstevel@tonic-gate	    </form>
11947c478bd9Sstevel@tonic-gate	  </th>
1195daaffb31Sdp	</tr>
11967c478bd9Sstevel@tonic-gate    </table>
11977c478bd9Sstevel@tonic-gate  </body>
11987c478bd9Sstevel@tonic-gate</html>
11997c478bd9Sstevel@tonic-gateEOF
12007c478bd9Sstevel@tonic-gate}
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate
1203daaffb31Sdp
1204daaffb31Sdp#
1205daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1206daaffb31Sdp#
1207daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1208daaffb31Sdp# context or unified diffs.
1209daaffb31Sdp#
12107c478bd9Sstevel@tonic-gatediff_to_html()
12117c478bd9Sstevel@tonic-gate{
12127c478bd9Sstevel@tonic-gate	TNAME=$1
1213daaffb31Sdp	TPATH=$2
1214daaffb31Sdp	DIFFTYPE=$3
1215daaffb31Sdp	COMMENT=$4
1216daaffb31Sdp
1217daaffb31Sdp	print "$HTML<head>$STDHEAD"
1218daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1219daaffb31Sdp
1220daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1221daaffb31Sdp		print "$UDIFFCSS"
1222daaffb31Sdp	fi
1223daaffb31Sdp
1224daaffb31Sdp	cat <<-EOF
1225daaffb31Sdp	</head>
1226daaffb31Sdp	<body id="SUNWwebrev">
1227daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1228daaffb31Sdp	<pre>$COMMENT</pre>
1229daaffb31Sdp        <pre>
1230daaffb31Sdp	EOF
12317c478bd9Sstevel@tonic-gate
1232cdf0c1d5Smjnelson	html_quote | $AWK '
1233daaffb31Sdp	/^--- new/	{ next }
1234daaffb31Sdp	/^\+\+\+ new/	{ next }
1235daaffb31Sdp	/^--- old/	{ next }
1236daaffb31Sdp	/^\*\*\* old/	{ next }
1237daaffb31Sdp	/^\*\*\*\*/	{ next }
12387c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1239cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1240daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1241daaffb31Sdp			  next}
1242daaffb31Sdp
1243cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1244daaffb31Sdp			  next}
1245daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1246daaffb31Sdp			  next}
1247daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1248daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1249daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1250daaffb31Sdp			{printf "%s\n", $0; next}
12517c478bd9Sstevel@tonic-gate	'
1252daaffb31Sdp
1253daaffb31Sdp	print "</pre></body></html>\n"
12547c478bd9Sstevel@tonic-gate}
12557c478bd9Sstevel@tonic-gate
12567c478bd9Sstevel@tonic-gate
1257daaffb31Sdp#
1258daaffb31Sdp# source_to_html { new | old } <filename>
1259daaffb31Sdp#
1260daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1261daaffb31Sdp#
12627c478bd9Sstevel@tonic-gatesource_to_html()
12637c478bd9Sstevel@tonic-gate{
12647c478bd9Sstevel@tonic-gate	WHICH=$1
12657c478bd9Sstevel@tonic-gate	TNAME=$2
12667c478bd9Sstevel@tonic-gate
1267daaffb31Sdp	print "$HTML<head>$STDHEAD"
1268cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1269daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1270daaffb31Sdp	print "<pre>"
1271cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1272daaffb31Sdp	print "</pre></body></html>"
12737c478bd9Sstevel@tonic-gate}
12747c478bd9Sstevel@tonic-gate
1275daaffb31Sdp#
1276cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1277daaffb31Sdp#
1278daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1279daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1280daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1281daaffb31Sdp# delta in that list (the first delta unique to the child).
12827c478bd9Sstevel@tonic-gate#
12837c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1284daaffb31Sdp#
1285daaffb31Sdpcomments_from_teamware()
12867c478bd9Sstevel@tonic-gate{
1287daaffb31Sdp	fmt=$1
1288daaffb31Sdp	pfile=$PWS/$2
1289daaffb31Sdp	cfile=$CWS/$3
12907c478bd9Sstevel@tonic-gate
1291cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1292cdf0c1d5Smjnelson		pfile=$RWS/$2
1293cdf0c1d5Smjnelson	fi
1294cdf0c1d5Smjnelson
1295daaffb31Sdp	if [[ -f $pfile ]]; then
1296cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
12977c478bd9Sstevel@tonic-gate	else
12987c478bd9Sstevel@tonic-gate		psid=1.1
12997c478bd9Sstevel@tonic-gate	fi
13007c478bd9Sstevel@tonic-gate
1301cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
13027c478bd9Sstevel@tonic-gate	N=${#sids[@]}
13037c478bd9Sstevel@tonic-gate
1304daaffb31Sdp	nawkprg='
1305daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1306daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1307daaffb31Sdp		NF == 0u	{ continue }
1308daaffb31Sdp		{if (p==0) continue; print $0 }'
1309daaffb31Sdp
13107c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
13117c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
13127c478bd9Sstevel@tonic-gate
1313daaffb31Sdp		if [[ $fmt == "text" ]]; then
1314cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1315cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1316daaffb31Sdp			return
1317daaffb31Sdp		fi
1318daaffb31Sdp
1319cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1320cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
13217c478bd9Sstevel@tonic-gate	fi
13227c478bd9Sstevel@tonic-gate}
13237c478bd9Sstevel@tonic-gate
1324daaffb31Sdp#
1325cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1326daaffb31Sdp#
1327cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1328cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1329cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1330cdf0c1d5Smjnelson# are turned into URLs.
1331cdf0c1d5Smjnelson#
1332cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1333daaffb31Sdp#
1334daaffb31Sdpcomments_from_wx()
13357c478bd9Sstevel@tonic-gate{
1336daaffb31Sdp	typeset fmt=$1
1337daaffb31Sdp	typeset p=$2
13387c478bd9Sstevel@tonic-gate
1339cdf0c1d5Smjnelson	comm=`$AWK '
1340daaffb31Sdp	$1 == "'$p'" {
13417c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
13427c478bd9Sstevel@tonic-gate		getline
13437c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
13447c478bd9Sstevel@tonic-gate		exit
1345daaffb31Sdp	}' < $wxfile`
1346daaffb31Sdp
1347cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1348cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1349cdf0c1d5Smjnelson	fi
1350cdf0c1d5Smjnelson
1351daaffb31Sdp	if [[ $fmt == "text" ]]; then
1352cdf0c1d5Smjnelson		print -- "$comm"
1353daaffb31Sdp		return
1354daaffb31Sdp	fi
1355daaffb31Sdp
1356cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1357cdf0c1d5Smjnelson
13587c478bd9Sstevel@tonic-gate}
13597c478bd9Sstevel@tonic-gate
13607c478bd9Sstevel@tonic-gate#
1361daaffb31Sdp# getcomments {text|html} filepath parentpath
1362daaffb31Sdp#
1363daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1364daaffb31Sdp#
1365daaffb31Sdpgetcomments()
1366daaffb31Sdp{
1367daaffb31Sdp	typeset fmt=$1
1368daaffb31Sdp	typeset p=$2
1369daaffb31Sdp	typeset pp=$3
13707c478bd9Sstevel@tonic-gate
13713df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
13723df69ef3SDarren Moffat		return
13733df69ef3SDarren Moffat	fi
1374cdf0c1d5Smjnelson	#
1375cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1376cdf0c1d5Smjnelson	# will be used there, too
1377cdf0c1d5Smjnelson	#
1378daaffb31Sdp	if [[ -n $wxfile ]]; then
1379daaffb31Sdp		comments_from_wx $fmt $p
1380daaffb31Sdp	else
1381daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1382daaffb31Sdp			comments_from_teamware $fmt $pp $p
1383daaffb31Sdp		fi
1384daaffb31Sdp	fi
1385daaffb31Sdp}
1386daaffb31Sdp
1387daaffb31Sdp#
1388daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1389daaffb31Sdp#
1390daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1391daaffb31Sdp#
1392daaffb31Sdpfunction printCI
1393daaffb31Sdp{
1394daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1395daaffb31Sdp	typeset str
1396daaffb31Sdp	if (( tot == 1 )); then
1397daaffb31Sdp		str="line"
1398daaffb31Sdp	else
1399daaffb31Sdp		str="lines"
1400daaffb31Sdp	fi
1401daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1402daaffb31Sdp	    $tot $str $ins $del $mod $unc
1403daaffb31Sdp}
1404daaffb31Sdp
1405daaffb31Sdp
1406daaffb31Sdp#
1407daaffb31Sdp# difflines <oldfile> <newfile>
1408daaffb31Sdp#
1409daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1410daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1411daaffb31Sdp#
14127c478bd9Sstevel@tonic-gatefunction difflines
14137c478bd9Sstevel@tonic-gate{
1414daaffb31Sdp	integer tot mod del ins unc err
14157c478bd9Sstevel@tonic-gate	typeset filename
14167c478bd9Sstevel@tonic-gate
1417cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1418daaffb31Sdp	# Change range of lines: N,Nc
14197c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
14207c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
14217c478bd9Sstevel@tonic-gate		if (n != 2) {
14227c478bd9Sstevel@tonic-gate		    error=2
14237c478bd9Sstevel@tonic-gate		    exit;
14247c478bd9Sstevel@tonic-gate		}
1425daaffb31Sdp		#
1426daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1427daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1428daaffb31Sdp		#
14297c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1430daaffb31Sdp
1431daaffb31Sdp		#
1432daaffb31Sdp		# Now count replacement lines: each represents a change instead
1433daaffb31Sdp		# of a delete, so increment c and decrement r.
1434daaffb31Sdp		#
14357c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
14367c478bd9Sstevel@tonic-gate			c++;
14377c478bd9Sstevel@tonic-gate			r--;
14387c478bd9Sstevel@tonic-gate		}
1439daaffb31Sdp		#
1440daaffb31Sdp		# If there were more replacement lines than original lines,
1441daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1442daaffb31Sdp		# but there are r changes that should be counted as adds, and
1443daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1444daaffb31Sdp		#
14457c478bd9Sstevel@tonic-gate		if (r < 0) {
14467c478bd9Sstevel@tonic-gate			a-=r;
14477c478bd9Sstevel@tonic-gate			c+=r;
14487c478bd9Sstevel@tonic-gate		}
1449daaffb31Sdp
1450daaffb31Sdp		#
1451daaffb31Sdp		# If there were more original lines than replacement lines, then
1452daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1453daaffb31Sdp		#
14547c478bd9Sstevel@tonic-gate		if (r > 0) {
14557c478bd9Sstevel@tonic-gate			d+=r;
14567c478bd9Sstevel@tonic-gate		}
14577c478bd9Sstevel@tonic-gate		next;
14587c478bd9Sstevel@tonic-gate	}
14597c478bd9Sstevel@tonic-gate
1460daaffb31Sdp	# Change lines: Nc
14617c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1462daaffb31Sdp		# The first line is a replacement; any more are additions.
14637c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
14647c478bd9Sstevel@tonic-gate			c++;
14657c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
14667c478bd9Sstevel@tonic-gate		}
14677c478bd9Sstevel@tonic-gate		next;
14687c478bd9Sstevel@tonic-gate	}
14697c478bd9Sstevel@tonic-gate
1470daaffb31Sdp	# Add lines: both Na and N,Na
14717c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
14727c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
14737c478bd9Sstevel@tonic-gate		next;
14747c478bd9Sstevel@tonic-gate	}
14757c478bd9Sstevel@tonic-gate
1476daaffb31Sdp	# Delete range of lines: N,Nd
14777c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
14787c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
14797c478bd9Sstevel@tonic-gate		if (n != 2) {
14807c478bd9Sstevel@tonic-gate			error=2
14817c478bd9Sstevel@tonic-gate			exit;
14827c478bd9Sstevel@tonic-gate		}
1483daaffb31Sdp		#
1484daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1485daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1486daaffb31Sdp		#
14877c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
14887c478bd9Sstevel@tonic-gate		d+=r;
14897c478bd9Sstevel@tonic-gate		next;
14907c478bd9Sstevel@tonic-gate	}
14917c478bd9Sstevel@tonic-gate
1492daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
14937c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
14947c478bd9Sstevel@tonic-gate
1495daaffb31Sdp	# Should not get here!
14967c478bd9Sstevel@tonic-gate	{
14977c478bd9Sstevel@tonic-gate		error=1;
14987c478bd9Sstevel@tonic-gate		exit;
14997c478bd9Sstevel@tonic-gate	}
15007c478bd9Sstevel@tonic-gate
1501daaffb31Sdp	# Finish off - print results
15027c478bd9Sstevel@tonic-gate	END {
1503daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
15047c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
15057c478bd9Sstevel@tonic-gate	}' )
15067c478bd9Sstevel@tonic-gate
1507cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
15087c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1509daaffb31Sdp		print "Unexpected Error occurred reading" \
1510daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1511daaffb31Sdp		return
1512daaffb31Sdp	fi
1513daaffb31Sdp
15147c478bd9Sstevel@tonic-gate	# Accumulate totals
15157c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1516daaffb31Sdp	(( TMOD += mod ))
15177c478bd9Sstevel@tonic-gate	(( TDEL += del ))
15187c478bd9Sstevel@tonic-gate	(( TINS += ins ))
15197c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1520cdf0c1d5Smjnelson	unc=`wc -l < $1`
15217c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1522daaffb31Sdp		(( unc -= del + mod ))
15237c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
15247c478bd9Sstevel@tonic-gate	fi
15257c478bd9Sstevel@tonic-gate	# print summary
1526daaffb31Sdp	print "<span class=\"lineschanged\">"
1527daaffb31Sdp	printCI $tot $ins $del $mod $unc
1528daaffb31Sdp	print "</span>"
15297c478bd9Sstevel@tonic-gate}
15307c478bd9Sstevel@tonic-gate
1531daaffb31Sdp
15327c478bd9Sstevel@tonic-gate#
1533daaffb31Sdp# flist_from_wx
1534daaffb31Sdp#
1535daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1536daaffb31Sdp# Sets the global 'wxfile' variable.
1537daaffb31Sdp#
1538daaffb31Sdpfunction flist_from_wx
15397c478bd9Sstevel@tonic-gate{
1540daaffb31Sdp	typeset argfile=$1
1541daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1542daaffb31Sdp		#
1543daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1544daaffb31Sdp		# because the webrev does a "cd" later on.
1545daaffb31Sdp		#
1546daaffb31Sdp		wxfile=$PWD/$argfile
15477c478bd9Sstevel@tonic-gate	else
1548daaffb31Sdp		wxfile=$argfile
15497c478bd9Sstevel@tonic-gate	fi
15507c478bd9Sstevel@tonic-gate
1551cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
15527c478bd9Sstevel@tonic-gate	  while (getline) {
15537c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
15547c478bd9Sstevel@tonic-gate		if (c > 0) print
15557c478bd9Sstevel@tonic-gate	  }
1556daaffb31Sdp	}' $wxfile > $FLIST
15577c478bd9Sstevel@tonic-gate
1558daaffb31Sdp	print " Done."
1559daaffb31Sdp}
15607c478bd9Sstevel@tonic-gate
1561daaffb31Sdp#
1562daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1563daaffb31Sdp#
1564daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1565daaffb31Sdp# names may come from the "update/create" messages and others from the
1566daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1567daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1568daaffb31Sdp# -n as well, but remove them if they are already defined.
1569daaffb31Sdp#
1570daaffb31Sdpfunction flist_from_teamware
1571daaffb31Sdp{
1572cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1573daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1574daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1575daaffb31Sdp			    "valid teamware workspace"
15767c478bd9Sstevel@tonic-gate			exit 1
15777c478bd9Sstevel@tonic-gate		fi
1578daaffb31Sdp		parent_args="-p $codemgr_parent"
15797c478bd9Sstevel@tonic-gate	fi
15807c478bd9Sstevel@tonic-gate
1581daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
15827c478bd9Sstevel@tonic-gate
1583daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1584cdf0c1d5Smjnelson	    $AWK '
1585daaffb31Sdp		/^update:|^create:/	{print $2}
1586daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1587daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1588daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1589daaffb31Sdp		NF == 0			{p=0 ; continue}
1590daaffb31Sdp		/^rename/		{old=$3}
1591daaffb31Sdp		$1 == "to:"		{print $2, old}
1592daaffb31Sdp		/^"/			{continue}
1593daaffb31Sdp		p == 1			{print $1}' |
1594daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
15957c478bd9Sstevel@tonic-gate
1596daaffb31Sdp	print " Done."
1597daaffb31Sdp}
1598daaffb31Sdp
1599cdf0c1d5Smjnelson#
1600cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1601cdf0c1d5Smjnelson#
1602cdf0c1d5Smjnelsonfunction hg_active_wxfile
1603cdf0c1d5Smjnelson{
1604cdf0c1d5Smjnelson	typeset child=$1
1605cdf0c1d5Smjnelson	typeset parent=$2
1606cdf0c1d5Smjnelson
1607cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
16089a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1609cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1610cdf0c1d5Smjnelson}
1611cdf0c1d5Smjnelson
1612cdf0c1d5Smjnelson#
1613cdf0c1d5Smjnelson# flist_from_mercurial
1614cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1615cdf0c1d5Smjnelson# flist_from_wx
1616cdf0c1d5Smjnelson#
1617cdf0c1d5Smjnelsonfunction flist_from_mercurial
1618cdf0c1d5Smjnelson{
1619cdf0c1d5Smjnelson	typeset child=$1
1620cdf0c1d5Smjnelson	typeset parent=$2
1621cdf0c1d5Smjnelson
1622cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1623cdf0c1d5Smjnelson
1624cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1625cdf0c1d5Smjnelson		print		# Blank line for the \c above
1626cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1627cdf0c1d5Smjnelson		exit 1
1628cdf0c1d5Smjnelson	fi
1629cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1630cdf0c1d5Smjnelson
1631cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1632cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1633cdf0c1d5Smjnelson}
1634cdf0c1d5Smjnelson
1635cdf0c1d5Smjnelson#
1636cdf0c1d5Smjnelson# flist_from_subversion
1637cdf0c1d5Smjnelson#
1638cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1639cdf0c1d5Smjnelson#
1640cdf0c1d5Smjnelsonfunction flist_from_subversion
1641cdf0c1d5Smjnelson{
1642cdf0c1d5Smjnelson	CWS=$1
1643cdf0c1d5Smjnelson	OLDPWD=$2
1644cdf0c1d5Smjnelson
1645cdf0c1d5Smjnelson	cd $CWS
1646cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1647cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1648cdf0c1d5Smjnelson	print -u2 " Done."
1649cdf0c1d5Smjnelson	cd $OLDPWD
1650cdf0c1d5Smjnelson}
1651cdf0c1d5Smjnelson
1652daaffb31Sdpfunction env_from_flist
1653daaffb31Sdp{
1654daaffb31Sdp	[[ -r $FLIST ]] || return
1655daaffb31Sdp
1656daaffb31Sdp	#
1657daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1658daaffb31Sdp	# list.  Then copy those into our local versions of those
1659daaffb31Sdp	# variables if they have not been set already.
1660daaffb31Sdp	#
166102d26c39SVladimir Kotal	eval `sed -e "s/#.*$//" $FLIST | $GREP = `
16627c478bd9Sstevel@tonic-gate
1663cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1664cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1665cdf0c1d5Smjnelson		export CODEMGR_WS
1666cdf0c1d5Smjnelson	fi
16677c478bd9Sstevel@tonic-gate
1668daaffb31Sdp	#
1669daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1670daaffb31Sdp	#
1671cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1672daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1673cdf0c1d5Smjnelson		export CODEMGR_PARENT
1674daaffb31Sdp	fi
1675daaffb31Sdp}
1676daaffb31Sdp
167714983201Sdpfunction look_for_prog
167814983201Sdp{
167914983201Sdp	typeset path
168014983201Sdp	typeset ppath
168114983201Sdp	typeset progname=$1
168214983201Sdp
168314983201Sdp	ppath=$PATH
168414983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
168514983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1686cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
168714983201Sdp
168814983201Sdp	PATH=$ppath prog=`whence $progname`
168914983201Sdp	if [[ -n $prog ]]; then
169014983201Sdp		print $prog
169114983201Sdp	fi
169214983201Sdp}
169314983201Sdp
1694cdf0c1d5Smjnelsonfunction get_file_mode
1695cdf0c1d5Smjnelson{
1696cdf0c1d5Smjnelson	$PERL -e '
1697cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1698cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1699cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1700cdf0c1d5Smjnelson			exit 0;
1701cdf0c1d5Smjnelson		} else {
1702cdf0c1d5Smjnelson			exit 1;
1703cdf0c1d5Smjnelson		}
1704cdf0c1d5Smjnelson	    ' $1
1705cdf0c1d5Smjnelson}
1706cdf0c1d5Smjnelson
1707cdf0c1d5Smjnelsonfunction build_old_new_teamware
1708cdf0c1d5Smjnelson{
1709cdf0c1d5Smjnelson	typeset olddir="$1"
1710cdf0c1d5Smjnelson	typeset newdir="$2"
1711cdf0c1d5Smjnelson
1712cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1713cdf0c1d5Smjnelson	# get a readonly copy.
1714cdf0c1d5Smjnelson
1715cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1716cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1717cdf0c1d5Smjnelson	fi
1718cdf0c1d5Smjnelson
1719cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1720cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1721cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1722cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1723cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1724cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1725cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1726cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1727cdf0c1d5Smjnelson	# permissions that would result after check in.
1728cdf0c1d5Smjnelson
1729cdf0c1d5Smjnelson	#
1730cdf0c1d5Smjnelson	# Snag new version of file.
1731cdf0c1d5Smjnelson	#
1732cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1733cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1734cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1735cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1736cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1737cdf0c1d5Smjnelson	fi
1738cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1739cdf0c1d5Smjnelson
1740cdf0c1d5Smjnelson	#
1741cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1742cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1743cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1744cdf0c1d5Smjnelson	#
1745cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1746cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1747cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1748cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1749cdf0c1d5Smjnelson		# the old file.
1750cdf0c1d5Smjnelson
1751cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1752cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1753cdf0c1d5Smjnelson	else
1754cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1755cdf0c1d5Smjnelson			real_parent=$PWS
1756cdf0c1d5Smjnelson		else
1757cdf0c1d5Smjnelson			real_parent=$RWS
1758cdf0c1d5Smjnelson		fi
1759cdf0c1d5Smjnelson
1760cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1761cdf0c1d5Smjnelson
1762cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1763cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1764cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1765cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1766cdf0c1d5Smjnelson			else
1767cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1768cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1769cdf0c1d5Smjnelson			fi
1770cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1771cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1772cdf0c1d5Smjnelson		fi
1773cdf0c1d5Smjnelson	fi
1774cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1775cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1776cdf0c1d5Smjnelson	fi
1777cdf0c1d5Smjnelson}
1778cdf0c1d5Smjnelson
1779cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1780cdf0c1d5Smjnelson{
1781cdf0c1d5Smjnelson	typeset olddir="$1"
1782cdf0c1d5Smjnelson	typeset newdir="$2"
1783cdf0c1d5Smjnelson	typeset old_mode=
1784cdf0c1d5Smjnelson	typeset new_mode=
1785cdf0c1d5Smjnelson	typeset file
1786cdf0c1d5Smjnelson
1787cdf0c1d5Smjnelson	#
1788cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1789cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1790cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1791cdf0c1d5Smjnelson	#
1792cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1793cdf0c1d5Smjnelson		file="$PF"
1794cdf0c1d5Smjnelson	else
1795cdf0c1d5Smjnelson		file="$PDIR/$PF"
1796cdf0c1d5Smjnelson	fi
1797cdf0c1d5Smjnelson	file=`echo $file | sed 's#/#\\\/#g'`
1798cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1799cdf0c1d5Smjnelson	old_mode=`sed -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1800cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1801cdf0c1d5Smjnelson
1802cdf0c1d5Smjnelson	#
1803cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1804cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1805cdf0c1d5Smjnelson	#
1806cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1807cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1808cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1809cdf0c1d5Smjnelson			new_mode=755
1810cdf0c1d5Smjnelson		else
1811cdf0c1d5Smjnelson			new_mode=644
1812cdf0c1d5Smjnelson		fi
1813cdf0c1d5Smjnelson	fi
1814cdf0c1d5Smjnelson
1815cdf0c1d5Smjnelson	#
1816cdf0c1d5Smjnelson	# new version of the file.
1817cdf0c1d5Smjnelson	#
1818cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1819cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1820cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1821cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1822cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1823cdf0c1d5Smjnelson		else
1824cdf0c1d5Smjnelson			# should never happen
1825cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1826cdf0c1d5Smjnelson		fi
1827cdf0c1d5Smjnelson	fi
1828cdf0c1d5Smjnelson
1829cdf0c1d5Smjnelson	#
1830cdf0c1d5Smjnelson	# parent's version of the file
1831cdf0c1d5Smjnelson	#
1832cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1833cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1834cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1835cdf0c1d5Smjnelson	#
1836cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1837cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1838cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1839cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1840cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1841cdf0c1d5Smjnelson
184202d26c39SVladimir Kotal		if (( $? != 0 )); then
1843cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1844cdf0c1d5Smjnelson		else
1845cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1846cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1847cdf0c1d5Smjnelson			else
1848cdf0c1d5Smjnelson				# should never happen
1849cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1850cdf0c1d5Smjnelson			fi
1851cdf0c1d5Smjnelson		fi
1852cdf0c1d5Smjnelson	fi
1853cdf0c1d5Smjnelson}
1854cdf0c1d5Smjnelson
1855cdf0c1d5Smjnelsonfunction build_old_new_subversion
1856cdf0c1d5Smjnelson{
1857cdf0c1d5Smjnelson	typeset olddir="$1"
1858cdf0c1d5Smjnelson	typeset newdir="$2"
1859cdf0c1d5Smjnelson
1860cdf0c1d5Smjnelson	# Snag new version of file.
1861cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1862cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1863cdf0c1d5Smjnelson
1864cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1865cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1866cdf0c1d5Smjnelson	else
1867cdf0c1d5Smjnelson		# Get the parent's version of the file.
1868cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
1869cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
1870cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
1871cdf0c1d5Smjnelson		fi
1872cdf0c1d5Smjnelson	fi
1873cdf0c1d5Smjnelson}
1874cdf0c1d5Smjnelson
1875cdf0c1d5Smjnelsonfunction build_old_new_unknown
1876cdf0c1d5Smjnelson{
1877cdf0c1d5Smjnelson	typeset olddir="$1"
1878cdf0c1d5Smjnelson	typeset newdir="$2"
1879cdf0c1d5Smjnelson
1880cdf0c1d5Smjnelson	#
1881cdf0c1d5Smjnelson	# Snag new version of file.
1882cdf0c1d5Smjnelson	#
1883cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1884cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1885cdf0c1d5Smjnelson
1886cdf0c1d5Smjnelson	#
1887cdf0c1d5Smjnelson	# Snag the parent's version of the file.
1888cdf0c1d5Smjnelson	#
1889cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
1890cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1891cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1892cdf0c1d5Smjnelson	fi
1893cdf0c1d5Smjnelson}
1894cdf0c1d5Smjnelson
1895cdf0c1d5Smjnelsonfunction build_old_new
1896cdf0c1d5Smjnelson{
1897cdf0c1d5Smjnelson	typeset WDIR=$1
1898cdf0c1d5Smjnelson	typeset PWS=$2
1899cdf0c1d5Smjnelson	typeset PDIR=$3
1900cdf0c1d5Smjnelson	typeset PF=$4
1901cdf0c1d5Smjnelson	typeset CWS=$5
1902cdf0c1d5Smjnelson	typeset DIR=$6
1903cdf0c1d5Smjnelson	typeset F=$7
1904cdf0c1d5Smjnelson
1905cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
1906cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
1907cdf0c1d5Smjnelson
1908cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
1909cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
1910cdf0c1d5Smjnelson
1911cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
1912cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
1913cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
1914cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
1915cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
1916cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
1917cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
1918cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
1919cdf0c1d5Smjnelson	fi
1920cdf0c1d5Smjnelson
1921cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
1922cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
1923cdf0c1d5Smjnelson		return 1
1924cdf0c1d5Smjnelson	fi
1925cdf0c1d5Smjnelson	return 0
1926cdf0c1d5Smjnelson}
1927cdf0c1d5Smjnelson
1928cdf0c1d5Smjnelson
1929daaffb31Sdp#
1930daaffb31Sdp# Usage message.
1931daaffb31Sdp#
1932daaffb31Sdpfunction usage
1933daaffb31Sdp{
1934daaffb31Sdp	print 'Usage:\twebrev [common-options]
1935daaffb31Sdp	webrev [common-options] ( <file> | - )
1936daaffb31Sdp	webrev [common-options] -w <wx file>
1937daaffb31Sdp
1938daaffb31SdpOptions:
1939ba44d8a2SVladimir Kotal	-D: delete remote webrev
1940daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
1941ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
1942ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
1943daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
1944daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
194502d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
194602d26c39SVladimir Kotal	-U: upload the webrev to remote destination
1947daaffb31Sdp	-w <wxfile>: Use specified wx active file.
1948daaffb31Sdp
1949daaffb31SdpEnvironment:
1950daaffb31Sdp	WDIR: Control the output directory.
1951daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
1952daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
1953ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
1954daaffb31Sdp
1955cdf0c1d5SmjnelsonSCM Specific Options:
1956cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
1957cdf0c1d5Smjnelson
1958daaffb31SdpSCM Environment:
1959cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
1960cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
1961daaffb31Sdp'
1962daaffb31Sdp
1963daaffb31Sdp	exit 2
1964daaffb31Sdp}
1965daaffb31Sdp
1966daaffb31Sdp#
1967daaffb31Sdp#
1968daaffb31Sdp# Main program starts here
1969daaffb31Sdp#
1970daaffb31Sdp#
1971daaffb31Sdp
1972daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1973daaffb31Sdp
1974daaffb31Sdpset +o noclobber
1975daaffb31Sdp
1976cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
1977cdf0c1d5Smjnelson
197814983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
197914983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
1980cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
1981cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
198214983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
198314983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
198414983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
198502d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
1986cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
1987cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
1988cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
1989cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
199002d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
199102d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
199202d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
199302d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
1994ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
1995cdf0c1d5Smjnelson
1996ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
1997ba44d8a2SVladimir KotalTRASH_DIR=".trash"
1998ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
199914983201Sdp
200014983201Sdpif [[ ! -x $PERL ]]; then
200114983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
200214983201Sdp	exit 1
2003daaffb31Sdpfi
200414983201Sdp
2005cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2006cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2007cdf0c1d5Smjnelson	exit 1
2008cdf0c1d5Smjnelsonfi
2009cdf0c1d5Smjnelson
201014983201Sdp#
201114983201Sdp# These aren't fatal, but we want to note them to the user.
201214983201Sdp# We don't warn on the absence of 'wx' until later when we've
201314983201Sdp# determined that we actually need to try to invoke it.
201414983201Sdp#
201514983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
201614983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
201714983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2018daaffb31Sdp
2019daaffb31Sdp# Declare global total counters.
2020daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2021daaffb31Sdp
2022ba44d8a2SVladimir Kotal# default remote host for upload/delete
2023ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2024ba44d8a2SVladimir Kotal
2025ba44d8a2SVladimir KotalDflag=
202614983201Sdpflist_mode=
202714983201Sdpflist_file=
2028daaffb31Sdpiflag=
202902d26c39SVladimir Kotallflag=
203002d26c39SVladimir KotalNflag=
203102d26c39SVladimir Kotalnflag=
203202d26c39SVladimir KotalOflag=
2033daaffb31Sdpoflag=
2034daaffb31Sdppflag=
203502d26c39SVladimir Kotaltflag=
203602d26c39SVladimir Kotaluflag=
203702d26c39SVladimir KotalUflag=
2038daaffb31Sdpwflag=
203902d26c39SVladimir Kotalremote_target=
2040ba44d8a2SVladimir Kotal
2041ba44d8a2SVladimir Kotal#
2042ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2043ba44d8a2SVladimir Kotal# 	with usr/src/tools/onbld/hgext/cdm.py
2044ba44d8a2SVladimir Kotal#
2045ba44d8a2SVladimir Kotalwhile getopts "i:o:p:lwONnt:UD" opt
2046daaffb31Sdpdo
2047daaffb31Sdp	case $opt in
2048ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2049ba44d8a2SVladimir Kotal
2050daaffb31Sdp	i)	iflag=1
2051daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2052daaffb31Sdp
2053daaffb31Sdp	#
2054daaffb31Sdp	# If -l has been specified, we need to abort further options
2055daaffb31Sdp	# processing, because subsequent arguments are going to be
2056daaffb31Sdp	# arguments to 'putback -n'.
2057daaffb31Sdp	#
2058daaffb31Sdp	l)	lflag=1
2059daaffb31Sdp		break;;
2060daaffb31Sdp
206102d26c39SVladimir Kotal	N)	Nflag=1;;
206202d26c39SVladimir Kotal
206302d26c39SVladimir Kotal	n)	nflag=1;;
2064daaffb31Sdp
2065daaffb31Sdp	O)	Oflag=1;;
2066daaffb31Sdp
206702d26c39SVladimir Kotal	o)	oflag=1
206802d26c39SVladimir Kotal		WDIR=$OPTARG;;
206902d26c39SVladimir Kotal
207002d26c39SVladimir Kotal	p)	pflag=1
207102d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
207202d26c39SVladimir Kotal
207302d26c39SVladimir Kotal	t)	tflag=1
207402d26c39SVladimir Kotal		remote_target=$OPTARG;;
207502d26c39SVladimir Kotal
207602d26c39SVladimir Kotal	U)	Uflag=1;;
207702d26c39SVladimir Kotal
207802d26c39SVladimir Kotal	w)	wflag=1;;
20793df69ef3SDarren Moffat
2080daaffb31Sdp	?)	usage;;
2081daaffb31Sdp	esac
2082daaffb31Sdpdone
2083daaffb31Sdp
2084daaffb31SdpFLIST=/tmp/$$.flist
2085daaffb31Sdp
2086daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2087daaffb31Sdp	usage
2088daaffb31Sdpfi
2089daaffb31Sdp
209002d26c39SVladimir Kotal# more sanity checking
209102d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2092ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2093ba44d8a2SVladimir Kotal	    "without -U"
209402d26c39SVladimir Kotal	exit 1
209502d26c39SVladimir Kotalfi
209602d26c39SVladimir Kotal
2097ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2098ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
209902d26c39SVladimir Kotal	exit 1
210002d26c39SVladimir Kotalfi
210102d26c39SVladimir Kotal
2102daaffb31Sdp#
2103daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2104daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2105daaffb31Sdp#
2106daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2107daaffb31Sdp	parent_webrev="$codemgr_parent"
2108daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2109daaffb31Sdpfi
2110daaffb31Sdp
2111daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2112daaffb31Sdp	shift $(($OPTIND - 1))
2113daaffb31Sdp
2114daaffb31Sdp	if [[ $1 == "-" ]]; then
2115daaffb31Sdp		cat > $FLIST
211614983201Sdp		flist_mode="stdin"
211714983201Sdp		flist_done=1
211814983201Sdp		shift
2119daaffb31Sdp	elif [[ -n $1 ]]; then
212014983201Sdp		if [[ ! -r $1 ]]; then
2121daaffb31Sdp			print -u2 "$1: no such file or not readable"
2122daaffb31Sdp			usage
2123daaffb31Sdp		fi
2124daaffb31Sdp		cat $1 > $FLIST
212514983201Sdp		flist_mode="file"
212614983201Sdp		flist_file=$1
212714983201Sdp		flist_done=1
212814983201Sdp		shift
2129daaffb31Sdp	else
213014983201Sdp		flist_mode="auto"
2131daaffb31Sdp	fi
2132daaffb31Sdpfi
2133daaffb31Sdp
2134daaffb31Sdp#
2135daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2136daaffb31Sdp# is in use.
2137daaffb31Sdp#
2138cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
2139cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2140cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2141cdf0c1d5Smjnelson	;;
2142cdf0c1d5Smjnelsonunknown)
2143cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2144cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2145cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
21467c478bd9Sstevel@tonic-gate		exit 1
21477c478bd9Sstevel@tonic-gate	fi
2148cdf0c1d5Smjnelson	;;
2149cdf0c1d5Smjnelson*)
2150cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2151cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2152cdf0c1d5Smjnelson		exit 1
2153cdf0c1d5Smjnelson	fi
2154cdf0c1d5Smjnelson	;;
2155cdf0c1d5Smjnelsonesac
21567c478bd9Sstevel@tonic-gate
2157daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2158daaffb31Sdp
2159daaffb31Sdpif [[ -n $lflag ]]; then
2160daaffb31Sdp	#
2161daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2162daaffb31Sdp	# then generate the file list by extracting file names from a
2163daaffb31Sdp	# putback -n.
2164daaffb31Sdp	#
2165daaffb31Sdp	shift $(($OPTIND - 1))
2166cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2167daaffb31Sdp		flist_from_teamware "$*"
2168cdf0c1d5Smjnelson	else
2169cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2170cdf0c1d5Smjnelson		exit 1
2171cdf0c1d5Smjnelson	fi
2172daaffb31Sdp	flist_done=1
2173daaffb31Sdp	shift $#
2174daaffb31Sdpelif [[ -n $wflag ]]; then
2175daaffb31Sdp	#
2176daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2177daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2178daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2179daaffb31Sdp	# in building the index.html file.
2180daaffb31Sdp	#
2181daaffb31Sdp	shift $(($OPTIND - 1))
2182daaffb31Sdp	wxfile=$1
2183daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2184daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2185daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2186daaffb31Sdp		fi
2187daaffb31Sdp	fi
2188daaffb31Sdp
2189daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2190daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2191daaffb31Sdp
2192cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2193cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2194cdf0c1d5Smjnelson		usage
2195cdf0c1d5Smjnelson	fi
2196cdf0c1d5Smjnelson
2197daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2198daaffb31Sdp	flist_from_wx $wxfile
2199daaffb31Sdp	flist_done=1
2200daaffb31Sdp	if [[ -n "$*" ]]; then
2201daaffb31Sdp		shift
2202daaffb31Sdp	fi
220314983201Sdpelif [[ $flist_mode == "stdin" ]]; then
220414983201Sdp	print -u2 " File list from: standard input"
220514983201Sdpelif [[ $flist_mode == "file" ]]; then
220614983201Sdp	print -u2 " File list from: $flist_file"
2207daaffb31Sdpfi
2208daaffb31Sdp
2209daaffb31Sdpif [[ $# -gt 0 ]]; then
221014983201Sdp	print -u2 "WARNING: unused arguments: $*"
2211daaffb31Sdpfi
2212daaffb31Sdp
2213daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
2214daaffb31Sdp	#
2215daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
2216daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
2217daaffb31Sdp	#
2218daaffb31Sdp	#      1) on the command line (only for the parent)
2219daaffb31Sdp	#      2) in the user environment
2220daaffb31Sdp	#      3) in the flist
2221daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
2222daaffb31Sdp	#
2223daaffb31Sdp
2224daaffb31Sdp	#
2225daaffb31Sdp	# Here is case (2): the user environment
2226daaffb31Sdp	#
2227daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2228daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2229daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
22307c478bd9Sstevel@tonic-gate		exit 1
22317c478bd9Sstevel@tonic-gate	fi
22327c478bd9Sstevel@tonic-gate
2233daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2234daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2235daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2236daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
22377c478bd9Sstevel@tonic-gate		exit 1
22387c478bd9Sstevel@tonic-gate	fi
22397c478bd9Sstevel@tonic-gate
2240daaffb31Sdp	#
2241daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2242daaffb31Sdp	# list, then see if we can get it by probing for wx.
2243daaffb31Sdp	#
224414983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
224514983201Sdp		if [[ ! -x $WX ]]; then
224614983201Sdp			print -u2 "WARNING: wx not found!"
2247daaffb31Sdp		fi
22487c478bd9Sstevel@tonic-gate
2249daaffb31Sdp		#
2250daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2251daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2252daaffb31Sdp		# hang asking us to initialize our wx information.
2253daaffb31Sdp		#
225414983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2255daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2256daaffb31Sdp			$WX list -w > $FLIST
2257daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2258daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2259daaffb31Sdp			print -u2 "done"
2260daaffb31Sdp			flist_done=1
2261daaffb31Sdp		fi
2262daaffb31Sdp	fi
2263daaffb31Sdp
2264daaffb31Sdp	#
2265daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2266daaffb31Sdp	# from the command line), eval it to extract environment variables from
2267daaffb31Sdp	# it: This is step (3).
2268daaffb31Sdp	#
2269daaffb31Sdp	env_from_flist
2270daaffb31Sdp
2271daaffb31Sdp	#
2272daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2273daaffb31Sdp	# it from teamware.
2274daaffb31Sdp	#
2275daaffb31Sdp	if [[ -z $flist_done ]]; then
2276daaffb31Sdp		flist_from_teamware
2277daaffb31Sdp		env_from_flist
2278daaffb31Sdp	fi
2279daaffb31Sdp
2280daaffb31Sdp	#
2281daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2282daaffb31Sdp	# from workspace.
2283daaffb31Sdp	#
2284cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2285daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2286daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2287daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2288daaffb31Sdp		exit 1
2289daaffb31Sdp	fi
2290daaffb31Sdp
2291daaffb31Sdp	#
2292cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2293cdf0c1d5Smjnelson	# webrev title.
2294cdf0c1d5Smjnelson	#
2295cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2296cdf0c1d5Smjnelson
2297cdf0c1d5Smjnelson	#
2298daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2299daaffb31Sdp	#
2300daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2301daaffb31Sdp	CWS=$codemgr_ws
2302daaffb31Sdp	PWS=$codemgr_parent
2303cdf0c1d5Smjnelson
2304cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2305cdf0c1d5Smjnelson
2306cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2307cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2308cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2309cdf0c1d5Smjnelson
2310cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2311cdf0c1d5Smjnelson
2312cdf0c1d5Smjnelson	#
2313cdf0c1d5Smjnelson	# Parent can either be specified with -p
2314cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2315cdf0c1d5Smjnelson	# or taken from hg's default path.
2316cdf0c1d5Smjnelson	#
2317cdf0c1d5Smjnelson
2318cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2319cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2320cdf0c1d5Smjnelson	fi
2321cdf0c1d5Smjnelson
2322cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2323cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2324cdf0c1d5Smjnelson	fi
2325cdf0c1d5Smjnelson
2326cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2327cdf0c1d5Smjnelson	CWS=$codemgr_ws
2328cdf0c1d5Smjnelson	PWS=$codemgr_parent
2329cdf0c1d5Smjnelson
2330cdf0c1d5Smjnelson	#
2331cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2332cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2333cdf0c1d5Smjnelson	#
2334cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2335cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2336cdf0c1d5Smjnelson	else
2337cdf0c1d5Smjnelson		real_parent=$PWS
2338cdf0c1d5Smjnelson	fi
2339cdf0c1d5Smjnelson
2340cdf0c1d5Smjnelson	#
2341cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2342cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2343cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2344cdf0c1d5Smjnelson	# files mentioned in the flist.
2345cdf0c1d5Smjnelson	#
2346cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2347cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2348cdf0c1d5Smjnelson		flist_done=1
2349cdf0c1d5Smjnelson	fi
2350cdf0c1d5Smjnelson
2351cdf0c1d5Smjnelson	#
2352cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2353cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2354cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2355cdf0c1d5Smjnelson	# in the user-specified flist.
2356cdf0c1d5Smjnelson	#
2357cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2358cdf0c1d5Smjnelson		env_from_flist
2359cdf0c1d5Smjnelson	fi
2360cdf0c1d5Smjnelson
2361cdf0c1d5Smjnelson	#
2362cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2363cdf0c1d5Smjnelson	#
2364cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2365cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2366cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2367cdf0c1d5Smjnelson		print " Done."
2368cdf0c1d5Smjnelson	fi
2369cdf0c1d5Smjnelson
2370cdf0c1d5Smjnelson	#
2371cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2372cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2373cdf0c1d5Smjnelson	# if we don't have one.
2374cdf0c1d5Smjnelson	#
2375cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
237602d26c39SVladimir Kotal		eval `sed -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2377cdf0c1d5Smjnelson	fi
2378cdf0c1d5Smjnelson
2379cdf0c1d5Smjnelson	#
2380cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2381cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2382cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2383cdf0c1d5Smjnelson	#
2384cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2385cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
238602d26c39SVladimir Kotal		    eval `sed -e "s/#.*$//" | $GREP HG_PARENT=`
2387cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2388cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2389cdf0c1d5Smjnelson		exit 1
2390cdf0c1d5Smjnelson	fi
2391cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2392cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2393cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2394cdf0c1d5Smjnelson	else
2395cdf0c1d5Smjnelson		svn info | while read line; do
2396cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2397cdf0c1d5Smjnelson				url=${line#URL: }
2398cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2399cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2400cdf0c1d5Smjnelson			fi
2401cdf0c1d5Smjnelson		done
2402cdf0c1d5Smjnelson
2403cdf0c1d5Smjnelson		rel=${url#$repo}
2404cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2405cdf0c1d5Smjnelson	fi
2406cdf0c1d5Smjnelson
2407cdf0c1d5Smjnelson	#
2408cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2409cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2410cdf0c1d5Smjnelson	#
2411cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2412cdf0c1d5Smjnelson
2413cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2414cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2415cdf0c1d5Smjnelson	fi
2416cdf0c1d5Smjnelsonelse
2417cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2418cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2419cdf0c1d5Smjnelson    else
2420cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2421cdf0c1d5Smjnelson    fi
2422cdf0c1d5Smjnelson
2423cdf0c1d5Smjnelson    env_from_flist
2424cdf0c1d5Smjnelson
2425cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2426cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2427cdf0c1d5Smjnelson	exit 1
2428cdf0c1d5Smjnelson    fi
2429cdf0c1d5Smjnelson
2430cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2431cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2432cdf0c1d5Smjnelson	exit 1
2433cdf0c1d5Smjnelson    fi
2434cdf0c1d5Smjnelson
2435cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2436cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2437daaffb31Sdpfi
2438daaffb31Sdp
2439daaffb31Sdp#
2440daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2441daaffb31Sdp# webrev-info file in the workspace directory.
2442daaffb31Sdp#
2443daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2444daaffb31Sdp	iflag=1
2445daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2446daaffb31Sdpfi
2447daaffb31Sdp
2448daaffb31Sdpif [[ -n $iflag ]]; then
2449daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2450daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2451daaffb31Sdp		    "not readable."
2452daaffb31Sdp		exit 1
2453daaffb31Sdp	else
2454daaffb31Sdp		#
2455daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2456daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2457daaffb31Sdp		#
2458daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2459daaffb31Sdp	fi
2460daaffb31Sdpfi
2461daaffb31Sdp
2462daaffb31Sdp#
2463daaffb31Sdp# Output directory.
2464daaffb31Sdp#
2465daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2466daaffb31Sdp
2467daaffb31Sdp#
246802d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
246902d26c39SVladimir Kotal# in the future this could potentially be an option.
2470daaffb31Sdp#
247102d26c39SVladimir Kotalif [[ -n $oflag ]]; then
247202d26c39SVladimir Kotal	WNAME=${WDIR##*/}
247302d26c39SVladimir Kotalelse
2474daaffb31Sdp	WNAME=${CWS##*/}
247502d26c39SVladimir Kotalfi
247602d26c39SVladimir Kotal
2477ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2478ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2479ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2480ba44d8a2SVladimir Kotal	# the default values.
2481ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2482ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2483ba44d8a2SVladimir Kotal	else
2484ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2485ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2486ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2487ba44d8a2SVladimir Kotal		# local webrev directory name.
2488ba44d8a2SVladimir Kotal		if [[ -z ${remote_target##*:} ]]; then
2489ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2490ba44d8a2SVladimir Kotal				dst=${remote_target}${WNAME}
2491ba44d8a2SVladimir Kotal			else
2492ba44d8a2SVladimir Kotal				dst=${remote_target}:${WNAME}
2493ba44d8a2SVladimir Kotal			fi
2494ba44d8a2SVladimir Kotal		fi
2495ba44d8a2SVladimir Kotal	fi
2496ba44d8a2SVladimir Kotalfi
2497ba44d8a2SVladimir Kotal
2498ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2499ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2500ba44d8a2SVladimir Kotal	delete_webrev 1
2501ba44d8a2SVladimir Kotal	exit $?
2502ba44d8a2SVladimir Kotalfi
2503ba44d8a2SVladimir Kotal
2504ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2505ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2506ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2507ba44d8a2SVladimir Kotal		delete_webrev 1
2508ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2509ba44d8a2SVladimir Kotal	fi
2510ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
251102d26c39SVladimir Kotal		upload_webrev
251202d26c39SVladimir Kotal		exit $?
251302d26c39SVladimir Kotal	fi
2514ba44d8a2SVladimir Kotalfi
2515daaffb31Sdp
2516e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
25177c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
25187c478bd9Sstevel@tonic-gatefi
2519daaffb31Sdp
2520daaffb31Sdpif [[ ! -d $WDIR ]]; then
2521daaffb31Sdp	mkdir -p $WDIR
2522ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
25237c478bd9Sstevel@tonic-gatefi
25247c478bd9Sstevel@tonic-gate
2525daaffb31Sdp#
2526daaffb31Sdp# Summarize what we're going to do.
2527daaffb31Sdp#
2528cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2529cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2530cdf0c1d5Smjnelsonelse
2531daaffb31Sdp	print "      Workspace: $CWS"
2532cdf0c1d5Smjnelsonfi
2533daaffb31Sdpif [[ -n $parent_webrev ]]; then
2534daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2535daaffb31Sdpelse
2536cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2537cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2538cdf0c1d5Smjnelson			| sed -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2539cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2540cdf0c1d5Smjnelson	else
2541daaffb31Sdp		print "Compare against: $PWS"
2542daaffb31Sdp	fi
2543cdf0c1d5Smjnelsonfi
2544daaffb31Sdp
2545daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2546daaffb31Sdpprint "      Output to: $WDIR"
2547daaffb31Sdp
2548daaffb31Sdp#
25497c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2550daaffb31Sdp#
2551daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
25527c478bd9Sstevel@tonic-gate
2553daaffb31Sdp#
2554daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2555daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2556daaffb31Sdp#
2557daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2558daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2559daaffb31Sdp[[ -n "$Oflag" ]] && \
2560daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
25617c478bd9Sstevel@tonic-gate
2562daaffb31Sdp#
2563daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2564daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2565daaffb31Sdp#
2566daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2567daaffb31Sdp#    SACURL.  See sac2url().
2568daaffb31Sdp#
2569daaffb31SdpSACURL='http://sac.eng.sun.com'
2570daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2571e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2572daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
25737c478bd9Sstevel@tonic-gate
2574daaffb31Sdprm -f $WDIR/$WNAME.patch
2575daaffb31Sdprm -f $WDIR/$WNAME.ps
2576daaffb31Sdprm -f $WDIR/$WNAME.pdf
25777c478bd9Sstevel@tonic-gate
2578daaffb31Sdptouch $WDIR/$WNAME.patch
25797c478bd9Sstevel@tonic-gate
2580daaffb31Sdpprint "   Output Files:"
2581daaffb31Sdp
2582daaffb31Sdp#
2583daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2584daaffb31Sdp#
2585daaffb31Sdpsed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2586daaffb31SdpFLIST=/tmp/$$.flist.clean
2587daaffb31Sdp
2588daaffb31Sdp#
2589cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2590cdf0c1d5Smjnelson#
2591cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2592cdf0c1d5Smjnelson	#
2593cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2594cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2595cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2596cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2597cdf0c1d5Smjnelson	#    keep only the old name.
2598cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2599cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2600cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2601cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2602cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2603cdf0c1d5Smjnelson	#
2604cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2605cdf0c1d5Smjnelson	sed '
2606cdf0c1d5Smjnelson		s#^[^ ]* ##
2607cdf0c1d5Smjnelson		s#/#\\\/#g
2608cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2609cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2610cdf0c1d5Smjnelson
2611cdf0c1d5Smjnelson	#
2612cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2613cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2614cdf0c1d5Smjnelson	#
2615cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2616cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2617cdf0c1d5Smjnelson	    sed -n -f $SEDFILE > $HG_PARENT_MANIFEST
2618cdf0c1d5Smjnelsonfi
2619cdf0c1d5Smjnelson
2620cdf0c1d5Smjnelson#
2621daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2622daaffb31Sdp#
2623daaffb31Sdpcat $FLIST | while read LINE
26247c478bd9Sstevel@tonic-gatedo
26257c478bd9Sstevel@tonic-gate	set - $LINE
26267c478bd9Sstevel@tonic-gate	P=$1
26277c478bd9Sstevel@tonic-gate
2628daaffb31Sdp	#
2629daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2630daaffb31Sdp	# file that has been modified or created in the child.  A file
2631daaffb31Sdp	# that is renamed in the child workspace has two names on the
2632daaffb31Sdp	# line: new name followed by the old name.
2633daaffb31Sdp	#
2634daaffb31Sdp	oldname=""
2635daaffb31Sdp	oldpath=""
2636daaffb31Sdp	rename=
2637daaffb31Sdp	if [[ $# -eq 2 ]]; then
26387c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2639daaffb31Sdp		oldname=" (was $PP)"
2640daaffb31Sdp		oldpath="$PP"
2641daaffb31Sdp		rename=1
26427c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2643daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
26447c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
26457c478bd9Sstevel@tonic-gate		fi
26467c478bd9Sstevel@tonic-gate
26477c478bd9Sstevel@tonic-gate		PF=${PP##*/}
26487c478bd9Sstevel@tonic-gate
26497c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2650daaffb31Sdp	        if [[ $DIR == $P ]]; then
26517c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
26527c478bd9Sstevel@tonic-gate		fi
26537c478bd9Sstevel@tonic-gate
26547c478bd9Sstevel@tonic-gate		F=${P##*/}
2655daaffb31Sdp
26567c478bd9Sstevel@tonic-gate        else
26577c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2658daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
26597c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
26607c478bd9Sstevel@tonic-gate		fi
26617c478bd9Sstevel@tonic-gate
26627c478bd9Sstevel@tonic-gate		F=${P##*/}
26637c478bd9Sstevel@tonic-gate
26647c478bd9Sstevel@tonic-gate		PP=$P
26657c478bd9Sstevel@tonic-gate		PDIR=$DIR
26667c478bd9Sstevel@tonic-gate		PF=$F
26677c478bd9Sstevel@tonic-gate	fi
26687c478bd9Sstevel@tonic-gate
2669daaffb31Sdp	COMM=`getcomments html $P $PP`
26707c478bd9Sstevel@tonic-gate
2671daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
26727c478bd9Sstevel@tonic-gate
26737c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
26747c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
26757c478bd9Sstevel@tonic-gate
2676daaffb31Sdp	#
2677daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2678daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2679e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2680daaffb31Sdp	#
2681e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2682daaffb31Sdp		pclosed=${P##usr/closed/}
2683e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2684e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2685daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2686daaffb31Sdp			    "mode review"
2687daaffb31Sdp			continue
2688daaffb31Sdp		fi
2689daaffb31Sdp	fi
2690daaffb31Sdp
2691daaffb31Sdp	#
2692cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2693daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2694daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2695daaffb31Sdp	#
2696daaffb31Sdp
2697cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
26987c478bd9Sstevel@tonic-gate	    continue
26997c478bd9Sstevel@tonic-gate
2700cdf0c1d5Smjnelson	#
2701cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2702cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2703cdf0c1d5Smjnelson	# consistent environment.
2704cdf0c1d5Smjnelson	#
2705cdf0c1d5Smjnelson	OWD=$PWD
2706daaffb31Sdp	cd $WDIR/raw_files
2707daaffb31Sdp	ofile=old/$PDIR/$PF
2708daaffb31Sdp	nfile=new/$DIR/$F
27097c478bd9Sstevel@tonic-gate
2710daaffb31Sdp	mv_but_nodiff=
2711daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2712daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2713daaffb31Sdp		mv_but_nodiff=1
2714daaffb31Sdp	fi
2715daaffb31Sdp
2716daaffb31Sdp	#
2717daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2718daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2719daaffb31Sdp	#
2720daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2721daaffb31Sdp	#	  diff and an 'add' diff
2722daaffb31Sdp	#	- new files and deleted files must be handled specially
2723daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2724daaffb31Sdp	#	  (and hence renames) as of this writing.
2725daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2726daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2727daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2728daaffb31Sdp	#         transformations:
2729daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2730daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2731daaffb31Sdp	#
2732daaffb31Sdp	cleanse_rmfile="sed 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2733daaffb31Sdp	cleanse_newfile="sed 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2734daaffb31Sdp
2735daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2736daaffb31Sdp	if [[ -z $rename ]]; then
2737e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2738daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2739daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2740e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2741daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2742daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2743daaffb31Sdp		else
2744daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2745daaffb31Sdp		fi
2746daaffb31Sdp	else
2747daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2748daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2749daaffb31Sdp
2750daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2751daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2752daaffb31Sdp
2753daaffb31Sdp	fi
2754daaffb31Sdp
2755daaffb31Sdp	#
2756daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2757daaffb31Sdp	# whole wad.
2758daaffb31Sdp	#
2759daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2760daaffb31Sdp
2761daaffb31Sdp	print " patch\c"
2762daaffb31Sdp
2763daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2764daaffb31Sdp
2765daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2766daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2767daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
27687c478bd9Sstevel@tonic-gate		print " cdiffs\c"
27697c478bd9Sstevel@tonic-gate
2770daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2771daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2772daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2773daaffb31Sdp
27747c478bd9Sstevel@tonic-gate		print " udiffs\c"
27757c478bd9Sstevel@tonic-gate
27767c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2777daaffb31Sdp			$WDIFF -c "$COMM" \
2778daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2779daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2780daaffb31Sdp			if [[ $? -eq 0 ]]; then
27817c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2782daaffb31Sdp			else
2783daaffb31Sdp				print " wdiffs[fail]\c"
2784daaffb31Sdp			fi
27857c478bd9Sstevel@tonic-gate		fi
27867c478bd9Sstevel@tonic-gate
2787daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2788daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
27897c478bd9Sstevel@tonic-gate		print " sdiffs\c"
27907c478bd9Sstevel@tonic-gate
27917c478bd9Sstevel@tonic-gate		print " frames\c"
27927c478bd9Sstevel@tonic-gate
27937c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
27947c478bd9Sstevel@tonic-gate
2795daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2796daaffb31Sdp
2797daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2798daaffb31Sdp		# renamed file: may also have differences
2799daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2800daaffb31Sdp	elif [[ -f $nfile ]]; then
28017c478bd9Sstevel@tonic-gate		# new file: count added lines
2802daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2803daaffb31Sdp	elif [[ -f $ofile ]]; then
28047c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2805daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
28067c478bd9Sstevel@tonic-gate	fi
28077c478bd9Sstevel@tonic-gate
2808daaffb31Sdp	#
2809daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
2810daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
2811daaffb31Sdp	# tree-killing to print out the contents of deleted files).
2812daaffb31Sdp	#
2813daaffb31Sdp	if [[ -f $nfile ]]; then
2814daaffb31Sdp		ocr=$ofile
2815daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
2816daaffb31Sdp
2817daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
2818daaffb31Sdp			textcomm=`getcomments text $P $PP`
281914983201Sdp			if [[ -x $CODEREVIEW ]]; then
282014983201Sdp				$CODEREVIEW -y "$textcomm" \
282114983201Sdp				    -e $ocr $nfile \
282214983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
282314983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
2824daaffb31Sdp				if [[ $? -eq 0 ]]; then
2825daaffb31Sdp					print " ps\c"
2826daaffb31Sdp				else
2827daaffb31Sdp					print " ps[fail]\c"
2828daaffb31Sdp				fi
2829daaffb31Sdp			fi
2830daaffb31Sdp		fi
283114983201Sdp	fi
2832daaffb31Sdp
2833cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
2834cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
28357c478bd9Sstevel@tonic-gate		print " old\c"
28367c478bd9Sstevel@tonic-gate	fi
28377c478bd9Sstevel@tonic-gate
2838daaffb31Sdp	if [[ -f $nfile ]]; then
2839daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
28407c478bd9Sstevel@tonic-gate		print " new\c"
28417c478bd9Sstevel@tonic-gate	fi
28427c478bd9Sstevel@tonic-gate
2843cdf0c1d5Smjnelson	cd $OWD
2844cdf0c1d5Smjnelson
2845daaffb31Sdp	print
28467c478bd9Sstevel@tonic-gatedone
28477c478bd9Sstevel@tonic-gate
2848daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
28497c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
2850daaffb31Sdp
285114983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
285214983201Sdp	print " Generating PDF: Skipped: no output available"
285314983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
285414983201Sdp	print " Generating PDF: \c"
285514983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
2856daaffb31Sdp	print "Done."
285714983201Sdpelse
285814983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
285914983201Sdpfi
28607c478bd9Sstevel@tonic-gate
2861e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
2862e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
2863e0e0293aSjmcp
2864e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
2865ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
2866e0e0293aSjmcpfi
2867e0e0293aSjmcp
28687c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
28697c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
28707c478bd9Sstevel@tonic-gate
28717c478bd9Sstevel@tonic-gatecd $CWS
28727c478bd9Sstevel@tonic-gate
28737c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
2874daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
28757c478bd9Sstevel@tonic-gate
2876daaffb31Sdpprint "     index.html: \c"
28777c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
28787c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
28797c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
28807c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
28817c478bd9Sstevel@tonic-gate
2882daaffb31Sdpprint "$HTML<head>$STDHEAD"
2883daaffb31Sdpprint "<title>$WNAME</title>"
2884daaffb31Sdpprint "</head>"
2885daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
2886daaffb31Sdpprint "<div class=\"summary\">"
2887daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
28887c478bd9Sstevel@tonic-gate
2889daaffb31Sdpprint "<table>"
28907c478bd9Sstevel@tonic-gate
2891daaffb31Sdp#
2892cdf0c1d5Smjnelson# Get the preparer's name:
2893daaffb31Sdp#
2894cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
2895cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
2896cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
2897cdf0c1d5Smjnelson#
2898cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
2899cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
2900cdf0c1d5Smjnelson#
2901cdf0c1d5Smjnelsonpreparer=
2902cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
2903cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
2904cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
2905cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
2906cdf0c1d5Smjnelson	fi
2907cdf0c1d5Smjnelsonfi
2908cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
2909cdf0c1d5Smjnelson	preparer=$(
2910cdf0c1d5Smjnelson	    $PERL -e '
2911cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
2912cdf0c1d5Smjnelson	        if ($login) {
2913cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
2914cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
2915cdf0c1d5Smjnelson	        } else {
2916cdf0c1d5Smjnelson	            printf "(unknown)\n";
2917cdf0c1d5Smjnelson	        }
2918cdf0c1d5Smjnelson	')
2919daaffb31Sdpfi
2920daaffb31Sdp
2921cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
2922cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
2923cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2924cdf0c1d5Smjnelson	print "(at $CWS_REV)"
2925cdf0c1d5Smjnelsonfi
2926cdf0c1d5Smjnelsonprint "</td></tr>"
2927daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
2928daaffb31Sdpif [[ -n $parent_webrev ]]; then
2929daaffb31Sdp	print "webrev at $parent_webrev"
2930daaffb31Sdpelse
2931daaffb31Sdp	print "$PWS"
2932cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
2933cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
2934cdf0c1d5Smjnelson	fi
2935daaffb31Sdpfi
2936daaffb31Sdpprint "</td></tr>"
2937daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
2938daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
2939daaffb31Sdpprint "</td></tr>"
2940daaffb31Sdp
2941daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
2942*371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
2943daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
2944*371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
2945daaffb31Sdpfi
2946daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
2947*371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
2948daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
2949*371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
2950daaffb31Sdpfi
2951daaffb31Sdp
2952daaffb31Sdpif [[ -n "$iflag" ]]; then
2953daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
2954daaffb31Sdp	cat /tmp/$$.include
2955daaffb31Sdp	print "</div></td></tr>"
2956daaffb31Sdpfi
2957daaffb31Sdpprint "</table>"
2958daaffb31Sdpprint "</div>"
2959daaffb31Sdp
2960daaffb31Sdp#
2961daaffb31Sdp# Second pass through the files: generate the rest of the index file
2962daaffb31Sdp#
2963daaffb31Sdpcat $FLIST | while read LINE
29647c478bd9Sstevel@tonic-gatedo
29657c478bd9Sstevel@tonic-gate	set - $LINE
29667c478bd9Sstevel@tonic-gate	P=$1
29677c478bd9Sstevel@tonic-gate
2968daaffb31Sdp	if [[ $# == 2 ]]; then
29697c478bd9Sstevel@tonic-gate		PP=$2
2970cdf0c1d5Smjnelson		oldname="$PP"
29717c478bd9Sstevel@tonic-gate	else
29727c478bd9Sstevel@tonic-gate		PP=$P
2973daaffb31Sdp		oldname=""
2974daaffb31Sdp	fi
2975daaffb31Sdp
2976cdf0c1d5Smjnelson	mv_but_nodiff=
2977cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
2978cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
2979cdf0c1d5Smjnelson		mv_but_nodiff=1
2980cdf0c1d5Smjnelson	fi
2981cdf0c1d5Smjnelson
2982daaffb31Sdp	DIR=${P%/*}
2983daaffb31Sdp	if [[ $DIR == $P ]]; then
2984daaffb31Sdp		DIR="."   # File at root of workspace
29857c478bd9Sstevel@tonic-gate	fi
29867c478bd9Sstevel@tonic-gate
29877c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
29887c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
29897c478bd9Sstevel@tonic-gate	# appear twice in the file list
29907c478bd9Sstevel@tonic-gate
29917c478bd9Sstevel@tonic-gate	F=$WDIR/$P
29927c478bd9Sstevel@tonic-gate
2993daaffb31Sdp	print "<p>"
29947c478bd9Sstevel@tonic-gate
29957c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
29967c478bd9Sstevel@tonic-gate
2997daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
2998*371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
2999*371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3000*371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3001*371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
30027c478bd9Sstevel@tonic-gate
3003daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3004*371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3005*371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
30067c478bd9Sstevel@tonic-gate		fi
30077c478bd9Sstevel@tonic-gate
3008*371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3009*371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
30107c478bd9Sstevel@tonic-gate
3011*371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3012*371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
30137c478bd9Sstevel@tonic-gate	else
3014daaffb31Sdp		print " ------ ------ ------"
30157c478bd9Sstevel@tonic-gate
3016daaffb31Sdp		if [[ -x $WDIFF ]]; then
30177c478bd9Sstevel@tonic-gate			print " ------"
30187c478bd9Sstevel@tonic-gate		fi
3019daaffb31Sdp
3020daaffb31Sdp		print " ------"
30217c478bd9Sstevel@tonic-gate	fi
30227c478bd9Sstevel@tonic-gate
30237c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
30247c478bd9Sstevel@tonic-gate
3025daaffb31Sdp	if [[ -f $F-.html ]]; then
3026*371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3027*371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
30287c478bd9Sstevel@tonic-gate	else
3029daaffb31Sdp		print " ---"
30307c478bd9Sstevel@tonic-gate	fi
30317c478bd9Sstevel@tonic-gate
30327c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
30337c478bd9Sstevel@tonic-gate
3034daaffb31Sdp	if [[ -f $F.html ]]; then
3035*371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3036*371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
30377c478bd9Sstevel@tonic-gate	else
3038daaffb31Sdp		print " ---"
30397c478bd9Sstevel@tonic-gate	fi
30407c478bd9Sstevel@tonic-gate
3041daaffb31Sdp	if [[ -f $F.patch ]]; then
3042*371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3043*371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3044daaffb31Sdp	else
3045daaffb31Sdp		print " -----"
3046daaffb31Sdp	fi
3047daaffb31Sdp
3048daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3049*371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3050*371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3051daaffb31Sdp	else
3052daaffb31Sdp		print " ---"
3053daaffb31Sdp	fi
3054daaffb31Sdp
3055cdf0c1d5Smjnelson	print "<b>$P</b>"
3056cdf0c1d5Smjnelson
3057cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3058cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
3059cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3060cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
3061cdf0c1d5Smjnelson		else
3062cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
3063cdf0c1d5Smjnelson		fi
3064cdf0c1d5Smjnelson	fi
3065cdf0c1d5Smjnelson
3066cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3067cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3068cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3069cdf0c1d5Smjnelson	fi
3070daaffb31Sdp
3071daaffb31Sdp	#
3072e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3073daaffb31Sdp	#
3074daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3075e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3076e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3077daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3078daaffb31Sdp			    "this review</i>"
3079daaffb31Sdp		fi
3080daaffb31Sdp	fi
3081daaffb31Sdp
3082daaffb31Sdp	print "</p>"
30837c478bd9Sstevel@tonic-gate	# Insert delta comments
30847c478bd9Sstevel@tonic-gate
3085daaffb31Sdp	print "<blockquote><pre>"
3086daaffb31Sdp	getcomments html $P $PP
3087daaffb31Sdp	print "</pre>"
30887c478bd9Sstevel@tonic-gate
30897c478bd9Sstevel@tonic-gate	# Add additional comments comment
30907c478bd9Sstevel@tonic-gate
3091daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
30927c478bd9Sstevel@tonic-gate
30937c478bd9Sstevel@tonic-gate	# Add count of changes.
30947c478bd9Sstevel@tonic-gate
3095daaffb31Sdp	if [[ -f $F.count ]]; then
30967c478bd9Sstevel@tonic-gate	    cat $F.count
30977c478bd9Sstevel@tonic-gate	    rm $F.count
30987c478bd9Sstevel@tonic-gate	fi
3099cdf0c1d5Smjnelson
3100cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3101cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3102cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3103cdf0c1d5Smjnelson
3104cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3105cdf0c1d5Smjnelson		# 1) New executable files
3106cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3107cdf0c1d5Smjnelson		# 3) Existing executable files
3108cdf0c1d5Smjnelson
3109cdf0c1d5Smjnelson		old_mode=
3110cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3111cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3112cdf0c1d5Smjnelson		fi
3113cdf0c1d5Smjnelson
3114cdf0c1d5Smjnelson		new_mode=
3115cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3116cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3117cdf0c1d5Smjnelson		fi
3118cdf0c1d5Smjnelson
3119cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3120cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3121cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3122cdf0c1d5Smjnelson			print "</span>"
3123cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3124cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3125cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3126cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3127cdf0c1d5Smjnelson			print "</span>"
3128cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3129cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3130cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3131cdf0c1d5Smjnelson			print "</span>"
3132cdf0c1d5Smjnelson		fi
3133cdf0c1d5Smjnelson	fi
3134cdf0c1d5Smjnelson
3135daaffb31Sdp	print "</blockquote>"
31367c478bd9Sstevel@tonic-gatedone
31377c478bd9Sstevel@tonic-gate
3138daaffb31Sdpprint
3139daaffb31Sdpprint
3140cac38512Smjnelsonprint "<hr></hr>"
3141daaffb31Sdpprint "<p style=\"font-size: small\">"
31429a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3143daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3144daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3145e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3146daaffb31Sdpprint "</body>"
3147daaffb31Sdpprint "</html>"
31487c478bd9Sstevel@tonic-gate
31497c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
31507c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
31517c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
31527c478bd9Sstevel@tonic-gate
3153daaffb31Sdpprint "Done."
315402d26c39SVladimir Kotal
3155ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3156ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3157ba44d8a2SVladimir Kotal	delete_webrev 1
3158ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3159ba44d8a2SVladimir Kotalfi
3160ba44d8a2SVladimir Kotal
316102d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
316202d26c39SVladimir Kotal	upload_webrev
316302d26c39SVladimir Kotal	exit $?
316402d26c39SVladimir Kotalfi
3165