xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 78add226e8da271dde8f3b5a91d340d1bf010151)
148fe8920SMark J. Nelson#!/usr/bin/ksh93 -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*78add226Sjmcp# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bd9Sstevel@tonic-gate#
26cdf0c1d5Smjnelson
27cdf0c1d5Smjnelson#
28daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
29daaffb31Sdp# suitable for doing a code review of source changes via a web page.
30daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
31daaffb31Sdp# type 'webrev -h'.
327c478bd9Sstevel@tonic-gate#
33daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
34daaffb31Sdp# man page.
357c478bd9Sstevel@tonic-gate#
36daaffb31Sdp
377c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
387c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
397c478bd9Sstevel@tonic-gateNEW_COLOR=blue
407c478bd9Sstevel@tonic-gate
41daaffb31SdpHTML='<?xml version="1.0"?>
42daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
43daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
44daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
45daaffb31Sdp
46daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
47daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
48daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
49daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
50daaffb31Sdp
51cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
52cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
53cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
54daaffb31Sdp<!--
55daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
56daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
57daaffb31Sdp   mechanism available in some browsers.
58daaffb31Sdp
59daaffb31Sdp   For example, to have all "removed" information be red instead of
60daaffb31Sdp   brown, set a rule in your userContent.css file like:
61daaffb31Sdp
62daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
63daaffb31Sdp-->
64daaffb31Sdp<style type="text/css" media="screen">
65daaffb31Sdpbody {
66daaffb31Sdp    background-color: #eeeeee;
67daaffb31Sdp}
68daaffb31Sdphr {
69daaffb31Sdp    border: none 0;
70daaffb31Sdp    border-top: 1px solid #aaa;
71daaffb31Sdp    height: 1px;
72daaffb31Sdp}
73daaffb31Sdpdiv.summary {
74daaffb31Sdp    font-size: .8em;
75daaffb31Sdp    border-bottom: 1px solid #aaa;
76daaffb31Sdp    padding-left: 1em;
77daaffb31Sdp    padding-right: 1em;
78daaffb31Sdp}
79daaffb31Sdpdiv.summary h2 {
80daaffb31Sdp    margin-bottom: 0.3em;
81daaffb31Sdp}
82daaffb31Sdpdiv.summary table th {
83daaffb31Sdp    text-align: right;
84daaffb31Sdp    vertical-align: top;
85daaffb31Sdp    white-space: nowrap;
86daaffb31Sdp}
87daaffb31Sdpspan.lineschanged {
88daaffb31Sdp    font-size: 0.7em;
89daaffb31Sdp}
90daaffb31Sdpspan.oldmarker {
91daaffb31Sdp    color: red;
92daaffb31Sdp    font-size: large;
93daaffb31Sdp    font-weight: bold;
94daaffb31Sdp}
95daaffb31Sdpspan.newmarker {
96daaffb31Sdp    color: green;
97daaffb31Sdp    font-size: large;
98daaffb31Sdp    font-weight: bold;
99daaffb31Sdp}
100daaffb31Sdpspan.removed {
101daaffb31Sdp    color: brown;
102daaffb31Sdp}
103daaffb31Sdpspan.changed {
104daaffb31Sdp    color: blue;
105daaffb31Sdp}
106daaffb31Sdpspan.new {
107daaffb31Sdp    color: blue;
108daaffb31Sdp    font-weight: bold;
109daaffb31Sdp}
110cdf0c1d5Smjnelsonspan.chmod {
111cdf0c1d5Smjnelson    font-size: 0.7em;
112cdf0c1d5Smjnelson    color: #db7800;
113cdf0c1d5Smjnelson}
114daaffb31Sdpa.print { font-size: x-small; }
115daaffb31Sdpa:hover { background-color: #ffcc99; }
116daaffb31Sdp</style>
117daaffb31Sdp
118daaffb31Sdp<style type="text/css" media="print">
119daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
120daaffb31Sdpspan.removed { color: #444; font-style: italic }
121daaffb31Sdpspan.changed { font-weight: bold; }
122daaffb31Sdpspan.new { font-weight: bold; }
123daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
124daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
125daaffb31Sdpa.print {display: none}
126daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
127daaffb31Sdp</style>
128daaffb31Sdp'
129daaffb31Sdp
130daaffb31Sdp#
131daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
132daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
133daaffb31Sdp#
134daaffb31SdpUDIFFCSS='
135daaffb31Sdp<style type="text/css" media="screen">
136daaffb31Sdpspan.new {
137daaffb31Sdp    color: blue;
138daaffb31Sdp    font-weight: normal;
139daaffb31Sdp}
140daaffb31Sdp</style>
141daaffb31Sdp'
142daaffb31Sdp
143b0088928SVladimir Kotal#
144b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
145b0088928SVladimir Kotal#
146b0088928SVladimir Kotalfunction print_upload_header
147b0088928SVladimir Kotal{
148b0088928SVladimir Kotal	typeset -r prefix=$1
149b0088928SVladimir Kotal	typeset display_target
150b0088928SVladimir Kotal
151b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
152b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
153b0088928SVladimir Kotal	else
154b0088928SVladimir Kotal		display_target=${remote_target}
155b0088928SVladimir Kotal	fi
156b0088928SVladimir Kotal
157b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
158b0088928SVladimir Kotal		display_target=${display_target}/
159b0088928SVladimir Kotal	fi
160b0088928SVladimir Kotal
161b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
162b0088928SVladimir Kotal	    "     Uploading: \c"
163b0088928SVladimir Kotal}
164b0088928SVladimir Kotal
165b0088928SVladimir Kotal#
16602d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
167b0088928SVladimir Kotal#
168ba44d8a2SVladimir Kotalfunction rsync_upload
16902d26c39SVladimir Kotal{
170b0088928SVladimir Kotal	if (( $# != 2 )); then
171b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
172b0088928SVladimir Kotal		exit 1
17302d26c39SVladimir Kotal	fi
17402d26c39SVladimir Kotal
175b0088928SVladimir Kotal	typeset -r dst=$1
176b0088928SVladimir Kotal	integer -r print_err_msg=$2
17702d26c39SVladimir Kotal
178b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
179b0088928SVladimir Kotal	print "rsync ... \c"
1808a34f8dcSVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
181b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
182b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
183b0088928SVladimir Kotal		return 1
184b0088928SVladimir Kotal	fi
185b0088928SVladimir Kotal	#
186b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
187b0088928SVladimir Kotal	# directory contents, not the whole directory.
188b0088928SVladimir Kotal	#
189b0088928SVladimir Kotal	typeset src_dir=$WDIR
190b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
191b0088928SVladimir Kotal		src_dir=${src_dir}/
192b0088928SVladimir Kotal	fi
193b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
19402d26c39SVladimir Kotal	if (( $? != 0 )); then
195b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
196b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
197b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
198b0088928SVladimir Kotal			print "error messages:"
199b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
200b0088928SVladimir Kotal			rm -f $err_msg
201b0088928SVladimir Kotal		fi
20202d26c39SVladimir Kotal		return 1
20302d26c39SVladimir Kotal	fi
20402d26c39SVladimir Kotal
205b0088928SVladimir Kotal	rm -f $err_msg
20602d26c39SVladimir Kotal	print "Done."
20702d26c39SVladimir Kotal	return 0
20802d26c39SVladimir Kotal}
20902d26c39SVladimir Kotal
210b0088928SVladimir Kotal#
211b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
212b0088928SVladimir Kotal# 1 on failure.
213b0088928SVladimir Kotal#
214b0088928SVladimir Kotalfunction remote_mkdirs
215b0088928SVladimir Kotal{
216b0088928SVladimir Kotal	typeset -r dir_spec=$1
2179d3952abSVladimir Kotal	typeset -r host_spec=$2
218b0088928SVladimir Kotal
219b0088928SVladimir Kotal	#
220b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
221b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
222b0088928SVladimir Kotal	# except the last one which will be created by scp.
223b0088928SVladimir Kotal	#
224b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
225b0088928SVladimir Kotal		print "mkdirs \c"
226b0088928SVladimir Kotal		#
227b0088928SVladimir Kotal		# Remove the last directory from directory specification.
228b0088928SVladimir Kotal		#
229b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
2308a34f8dcSVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP \
2318a34f8dcSVladimir Kotal		    /tmp/webrev_mkdir.XXXXXX )
232b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
233b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
234b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
235b0088928SVladimir Kotal			return 1
236b0088928SVladimir Kotal		fi
237b0088928SVladimir Kotal                OLDIFS=$IFS
238b0088928SVladimir Kotal                IFS=/
239b0088928SVladimir Kotal		typeset dir
240b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
241b0088928SVladimir Kotal			#
242b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
243b0088928SVladimir Kotal			# to avoid an error in case the directory already
244b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
245b0088928SVladimir Kotal			# there is one.
246b0088928SVladimir Kotal			#
247b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
248b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
249b0088928SVladimir Kotal                done
250b0088928SVladimir Kotal                IFS=$OLDIFS
2518a34f8dcSVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
252b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
253b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
254b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
255b0088928SVladimir Kotal			return 1
256b0088928SVladimir Kotal		fi
257b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
258b0088928SVladimir Kotal		if (( $? != 0 )); then
259b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
260b0088928SVladimir Kotal			print "error messages:"
261b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
262b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
263b0088928SVladimir Kotal			return 1
264b0088928SVladimir Kotal		fi
265b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
266b0088928SVladimir Kotal	fi
267b0088928SVladimir Kotal
268b0088928SVladimir Kotal	return 0
269b0088928SVladimir Kotal}
270b0088928SVladimir Kotal
271b0088928SVladimir Kotal#
27202d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
273b0088928SVladimir Kotal#
274ba44d8a2SVladimir Kotalfunction ssh_upload
27502d26c39SVladimir Kotal{
27602d26c39SVladimir Kotal	if (( $# != 1 )); then
277b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
278b0088928SVladimir Kotal		exit 1
27902d26c39SVladimir Kotal	fi
28002d26c39SVladimir Kotal
28102d26c39SVladimir Kotal	typeset dst=$1
28202d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
283ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
28402d26c39SVladimir Kotal
285b0088928SVladimir Kotal	#
286b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
287b0088928SVladimir Kotal	# because it will also print its progress.
288b0088928SVladimir Kotal	#
289b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
290b0088928SVladimir Kotal
291b0088928SVladimir Kotal	#
292b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
293b0088928SVladimir Kotal	# to perform it again.
294b0088928SVladimir Kotal	#
295ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
296b0088928SVladimir Kotal		#
297b0088928SVladimir Kotal		# We do not care about return value because this might be
298b0088928SVladimir Kotal		# the first time this directory is uploaded.
299b0088928SVladimir Kotal		#
300ba44d8a2SVladimir Kotal		delete_webrev 0
30102d26c39SVladimir Kotal	fi
30202d26c39SVladimir Kotal
303b0088928SVladimir Kotal	#
304b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
305b0088928SVladimir Kotal	# in remote_mkdirs function.
306b0088928SVladimir Kotal	#
3079d3952abSVladimir Kotal	remote_mkdirs ${dir_spec} ${host_spec}
30802d26c39SVladimir Kotal	if (( $? != 0 )); then
30902d26c39SVladimir Kotal		return 1
31002d26c39SVladimir Kotal	fi
31102d26c39SVladimir Kotal
312b0088928SVladimir Kotal	print "upload ... \c"
3138a34f8dcSVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
314b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
315b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
316b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
317b0088928SVladimir Kotal		return 1
318b0088928SVladimir Kotal	fi
31902d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
320b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
32102d26c39SVladimir Kotal	if (( $? != 0 )); then
322b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
323b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
324b0088928SVladimir Kotal		print "error messages:"
325b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
326b0088928SVladimir Kotal		rm -f ${scp_err_msg}
32702d26c39SVladimir Kotal		return 1
32802d26c39SVladimir Kotal	fi
32902d26c39SVladimir Kotal
330b0088928SVladimir Kotal	rm -f ${scp_err_msg}
33102d26c39SVladimir Kotal	print "Done."
33202d26c39SVladimir Kotal	return 0
33302d26c39SVladimir Kotal}
33402d26c39SVladimir Kotal
33502d26c39SVladimir Kotal#
336ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
337b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
338b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
339b0088928SVladimir Kotal# only performs deletion.
340ba44d8a2SVladimir Kotal#
341ba44d8a2SVladimir Kotalfunction delete_webrev
342ba44d8a2SVladimir Kotal{
343b0088928SVladimir Kotal	if (( $# < 1 )); then
344b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
345b0088928SVladimir Kotal		exit 1
346ba44d8a2SVladimir Kotal	fi
347ba44d8a2SVladimir Kotal
348b0088928SVladimir Kotal	integer -r check=$1
349b0088928SVladimir Kotal	integer delete_only=0
350b0088928SVladimir Kotal	if (( $# == 2 )); then
351b0088928SVladimir Kotal		delete_only=1
352b0088928SVladimir Kotal	fi
353b0088928SVladimir Kotal
354b0088928SVladimir Kotal	#
355ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
356b0088928SVladimir Kotal	#
357ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
358ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
359ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
360ba44d8a2SVladimir Kotal	typeset dir_rm
361ba44d8a2SVladimir Kotal
362b0088928SVladimir Kotal	#
363ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
364b0088928SVladimir Kotal	#
365ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
366ba44d8a2SVladimir Kotal		return 1
367ba44d8a2SVladimir Kotal	fi
368ba44d8a2SVladimir Kotal
369b0088928SVladimir Kotal	#
370ba44d8a2SVladimir Kotal	# Strip the ending slash.
371b0088928SVladimir Kotal	#
372ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
373ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
374ba44d8a2SVladimir Kotal	else
375ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
376ba44d8a2SVladimir Kotal	fi
377ba44d8a2SVladimir Kotal
378b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
379b0088928SVladimir Kotal		print "       Removing: \c"
380b0088928SVladimir Kotal	else
381b0088928SVladimir Kotal		print "rmdir \c"
382b0088928SVladimir Kotal	fi
383ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
384b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
385ba44d8a2SVladimir Kotal		return 1
386ba44d8a2SVladimir Kotal	fi
387ba44d8a2SVladimir Kotal
388b0088928SVladimir Kotal	#
389ba44d8a2SVladimir Kotal	# Prepare batch file.
390b0088928SVladimir Kotal	#
3918a34f8dcSVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
392ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
393b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
394ba44d8a2SVladimir Kotal		return 1
395ba44d8a2SVladimir Kotal	fi
396ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
397ba44d8a2SVladimir Kotal
398b0088928SVladimir Kotal	#
399ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
400b0088928SVladimir Kotal	#
4018a34f8dcSVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
402b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
403b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
404b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
405b0088928SVladimir Kotal		return 1
406b0088928SVladimir Kotal	fi
407b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
408ba44d8a2SVladimir Kotal	integer -r ret=$?
409ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
410ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
411b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
412b0088928SVladimir Kotal		print "error messages:"
413b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
414b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
415ba44d8a2SVladimir Kotal		return $ret
416ba44d8a2SVladimir Kotal	fi
417b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
418b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
419ba44d8a2SVladimir Kotal		print "Done."
420b0088928SVladimir Kotal	fi
421ba44d8a2SVladimir Kotal
422ba44d8a2SVladimir Kotal	return 0
423ba44d8a2SVladimir Kotal}
424ba44d8a2SVladimir Kotal
425ba44d8a2SVladimir Kotal#
42602d26c39SVladimir Kotal# Upload webrev to remote site
42702d26c39SVladimir Kotal#
428ba44d8a2SVladimir Kotalfunction upload_webrev
42902d26c39SVladimir Kotal{
430b0088928SVladimir Kotal	integer ret
43102d26c39SVladimir Kotal
43202d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
433b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
43402d26c39SVladimir Kotal		return 1
43502d26c39SVladimir Kotal	fi
43602d26c39SVladimir Kotal
437b0088928SVladimir Kotal	#
43802d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
43902d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
44002d26c39SVladimir Kotal	# target he probably knows what he is doing.
441b0088928SVladimir Kotal	#
44202d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
443ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
44402d26c39SVladimir Kotal			| $GREP closed >/dev/null
44502d26c39SVladimir Kotal		if (( $? == 0 )); then
446b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
447b0088928SVladimir Kotal			    "\"closed\" directory"
44802d26c39SVladimir Kotal			return 1
44902d26c39SVladimir Kotal		fi
45002d26c39SVladimir Kotal	fi
45102d26c39SVladimir Kotal
452b0088928SVladimir Kotal
453b0088928SVladimir Kotal	#
454b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
455b0088928SVladimir Kotal	#
45602d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
45702d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
458b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
459b0088928SVladimir Kotal			ret=$?
460b0088928SVladimir Kotal			return $ret
46102d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
46202d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
463b0088928SVladimir Kotal			ret=$?
464b0088928SVladimir Kotal			return $ret
46502d26c39SVladimir Kotal		fi
46602d26c39SVladimir Kotal	else
467b0088928SVladimir Kotal		#
468b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
469b0088928SVladimir Kotal		#
470b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
471b0088928SVladimir Kotal		ret=$?
472b0088928SVladimir Kotal		if (( $ret != 0 )); then
473b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
474ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
475b0088928SVladimir Kotal			ret=$?
47602d26c39SVladimir Kotal		fi
477b0088928SVladimir Kotal		return $ret
47802d26c39SVladimir Kotal	fi
47902d26c39SVladimir Kotal}
48002d26c39SVladimir Kotal
481daaffb31Sdp#
482371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
483371d72daSLubomir Sedlacik#
484371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
485371d72daSLubomir Sedlacik#
486371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
487371d72daSLubomir Sedlacik#
488371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
489371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
490371d72daSLubomir Sedlacik# a path delimiter.
491371d72daSLubomir Sedlacik#
49225cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make
49325cc4e45SVladimir Kotal# the substitution work with GNU sed.
49425cc4e45SVladimir Kotal#
495371d72daSLubomir Sedlacikfunction url_encode
496371d72daSLubomir Sedlacik{
497b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
498371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
499371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
500371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
50125cc4e45SVladimir Kotal	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
502371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
503371d72daSLubomir Sedlacik}
504371d72daSLubomir Sedlacik
505371d72daSLubomir Sedlacik#
506daaffb31Sdp# input_cmd | html_quote | output_cmd
507daaffb31Sdp# or
508daaffb31Sdp# html_quote filename | output_cmd
5097c478bd9Sstevel@tonic-gate#
5107c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5117c478bd9Sstevel@tonic-gate#
5127c478bd9Sstevel@tonic-gatehtml_quote()
5137c478bd9Sstevel@tonic-gate{
514b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5157c478bd9Sstevel@tonic-gate}
5167c478bd9Sstevel@tonic-gate
517daaffb31Sdp#
5180fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
519daaffb31Sdp#
5200fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
5210fd2682eSMark J. Nelson# relevant databases.
522daaffb31Sdp#
5230fd2682eSMark J. Nelsonits2url()
5247c478bd9Sstevel@tonic-gate{
5250fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
526daaffb31Sdp}
527daaffb31Sdp
5287c478bd9Sstevel@tonic-gate#
529daaffb31Sdp# strip_unchanged <infile> | output_cmd
5307c478bd9Sstevel@tonic-gate#
531daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
532daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5337c478bd9Sstevel@tonic-gate#
534daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
535daaffb31Sdp# identical lines are retained before and after the changed lines to
536daaffb31Sdp# provide some context.  The number of these lines is controlled by the
537cdf0c1d5Smjnelson# variable C in the $AWK script below.
538daaffb31Sdp#
539daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
540daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
541daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
542daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
543daaffb31Sdp#
544daaffb31Sdpstrip_unchanged()
545daaffb31Sdp{
546cdf0c1d5Smjnelson	$AWK '
547daaffb31Sdp	BEGIN	{ C = c = 20 }
548cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
549daaffb31Sdp		if (c > C) {
550daaffb31Sdp			c -= C
551daaffb31Sdp			inx = 0
552daaffb31Sdp			if (c > C) {
553cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
554daaffb31Sdp				inx = c % C
555daaffb31Sdp				c = C
556daaffb31Sdp			}
557daaffb31Sdp
558daaffb31Sdp			for (i = 0; i < c; i++)
559daaffb31Sdp				print ln[(inx + i) % C]
560daaffb31Sdp		}
561daaffb31Sdp		c = 0;
562daaffb31Sdp		print
563daaffb31Sdp		next
564daaffb31Sdp	}
565daaffb31Sdp	{	if (c >= C) {
566daaffb31Sdp			ln[c % C] = $0
567daaffb31Sdp			c++;
568daaffb31Sdp			next;
569daaffb31Sdp		}
570daaffb31Sdp		c++;
571daaffb31Sdp		print
572daaffb31Sdp	}
573cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
574daaffb31Sdp
575daaffb31Sdp	' $1
576daaffb31Sdp}
577daaffb31Sdp
578daaffb31Sdp#
579daaffb31Sdp# sdiff_to_html
580daaffb31Sdp#
581daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
582daaffb31Sdp# processes the diff output to present the files as an HTML document with
583daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
584daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
585daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
586daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
587daaffb31Sdp# e.g.
588daaffb31Sdp#
589daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
590daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
591daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
592daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
593daaffb31Sdp#          1234567</a> my bugid' > <file>.html
594daaffb31Sdp#
595daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
596daaffb31Sdp# in the webrev tree.
597daaffb31Sdp#
598daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
599daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
600daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
601daaffb31Sdp# the editing codes, e.g.
6027c478bd9Sstevel@tonic-gate#
6037c478bd9Sstevel@tonic-gate#      8c8
6047c478bd9Sstevel@tonic-gate#      57a61
6057c478bd9Sstevel@tonic-gate#      63c66,76
6067c478bd9Sstevel@tonic-gate#      68,93d80
6077c478bd9Sstevel@tonic-gate#      106d90
6087c478bd9Sstevel@tonic-gate#      108,110d91
6097c478bd9Sstevel@tonic-gate#
610daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
611daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
612daaffb31Sdp#  into something like this:
6137c478bd9Sstevel@tonic-gate#
6147c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6157c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
616daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6177c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6187c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6197c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6207c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6217c478bd9Sstevel@tonic-gate#        :               :
6227c478bd9Sstevel@tonic-gate#
623daaffb31Sdp#  This script is then run on the original source file to generate the
624daaffb31Sdp#  HTML that corresponds to the source file.
6257c478bd9Sstevel@tonic-gate#
626daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
627daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
628daaffb31Sdp#  notice that the changes are color-coded:
6297c478bd9Sstevel@tonic-gate#
6307c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6317c478bd9Sstevel@tonic-gate#   blue      - changed lines
6327c478bd9Sstevel@tonic-gate#   bold blue - new lines
6337c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6347c478bd9Sstevel@tonic-gate#
635daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
636daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
637daaffb31Sdp#  Teamware's filemerge tool.
638daaffb31Sdp#
639daaffb31Sdpsdiff_to_html()
640daaffb31Sdp{
6417c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6427c478bd9Sstevel@tonic-gate
643daaffb31Sdp	TNAME=$3
644daaffb31Sdp	TPATH=$4
645daaffb31Sdp	COMMENT=$5
646daaffb31Sdp
6477c478bd9Sstevel@tonic-gate	#
6487c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6497c478bd9Sstevel@tonic-gate	#
650cdf0c1d5Smjnelson	$AWK '
6517c478bd9Sstevel@tonic-gate	BEGIN	{
6527c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
653daaffb31Sdp		printf "function removed() "
654daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
655daaffb31Sdp		printf "function changed() "
656daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
657daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6587c478bd9Sstevel@tonic-gate}
6597c478bd9Sstevel@tonic-gate	/^</	{next}
6607c478bd9Sstevel@tonic-gate	/^>/	{next}
6617c478bd9Sstevel@tonic-gate	/^---/	{next}
662daaffb31Sdp
6637c478bd9Sstevel@tonic-gate	{
6647c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6657c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6667c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6677c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6687c478bd9Sstevel@tonic-gate			if (n == 1)
6697c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6707c478bd9Sstevel@tonic-gate			else
6717c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6727c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6737c478bd9Sstevel@tonic-gate			next
6747c478bd9Sstevel@tonic-gate		}
6757c478bd9Sstevel@tonic-gate
6767c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6777c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6787c478bd9Sstevel@tonic-gate		s = r[1];
6797c478bd9Sstevel@tonic-gate		if (n == 1)
6807c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6817c478bd9Sstevel@tonic-gate		else {
6827c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6837c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6847c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6857c478bd9Sstevel@tonic-gate		}
6867c478bd9Sstevel@tonic-gate		next
6877c478bd9Sstevel@tonic-gate	}
6887c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
6897c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
6907c478bd9Sstevel@tonic-gate		n1 = r[1]
6917c478bd9Sstevel@tonic-gate		n2 = r[2]
6927c478bd9Sstevel@tonic-gate		if (n == 1)
693daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
6947c478bd9Sstevel@tonic-gate		else
695daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
6967c478bd9Sstevel@tonic-gate		next
6977c478bd9Sstevel@tonic-gate	}
6987c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
6997c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7007c478bd9Sstevel@tonic-gate		n1 = r[1]
7017c478bd9Sstevel@tonic-gate		n2 = r[2]
7027c478bd9Sstevel@tonic-gate		final = n2
7037c478bd9Sstevel@tonic-gate		d1 = 0
7047c478bd9Sstevel@tonic-gate		if (n == 1)
705daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7067c478bd9Sstevel@tonic-gate		else {
7077c478bd9Sstevel@tonic-gate			d1 = n2 - n1
708daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7097c478bd9Sstevel@tonic-gate		}
7107c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7117c478bd9Sstevel@tonic-gate		n1 = r[1]
7127c478bd9Sstevel@tonic-gate		n2 = r[2]
7137c478bd9Sstevel@tonic-gate		if (m > 1) {
7147c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7157c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7167c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7177c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7187c478bd9Sstevel@tonic-gate			}
7197c478bd9Sstevel@tonic-gate		}
7207c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate		next
7237c478bd9Sstevel@tonic-gate	}
7247c478bd9Sstevel@tonic-gate	}
7257c478bd9Sstevel@tonic-gate
726daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
727daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate	#
7307c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7317c478bd9Sstevel@tonic-gate	#
732cdf0c1d5Smjnelson	$AWK '
7337c478bd9Sstevel@tonic-gate	BEGIN	{
7347c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
735daaffb31Sdp		printf "function new() "
736daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
737daaffb31Sdp		printf "function changed() "
738daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
739daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7407c478bd9Sstevel@tonic-gate	}
741daaffb31Sdp
7427c478bd9Sstevel@tonic-gate	/^</	{next}
7437c478bd9Sstevel@tonic-gate	/^>/	{next}
7447c478bd9Sstevel@tonic-gate	/^---/	{next}
745daaffb31Sdp
7467c478bd9Sstevel@tonic-gate	{
7477c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7487c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7497c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7507c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7517c478bd9Sstevel@tonic-gate			if (n == 1)
7527c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7537c478bd9Sstevel@tonic-gate			else
7547c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7557c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7567c478bd9Sstevel@tonic-gate			next
7577c478bd9Sstevel@tonic-gate		}
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7607c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7617c478bd9Sstevel@tonic-gate		s = r[1];
7627c478bd9Sstevel@tonic-gate		if (n == 1)
7637c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7647c478bd9Sstevel@tonic-gate		else {
7657c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7667c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7677c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7687c478bd9Sstevel@tonic-gate		}
7697c478bd9Sstevel@tonic-gate		next
7707c478bd9Sstevel@tonic-gate	}
7717c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7727c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7737c478bd9Sstevel@tonic-gate		n1 = r[1]
7747c478bd9Sstevel@tonic-gate		n2 = r[2]
7757c478bd9Sstevel@tonic-gate		if (n == 1)
776daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7777c478bd9Sstevel@tonic-gate		else
778daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7797c478bd9Sstevel@tonic-gate		next
7807c478bd9Sstevel@tonic-gate	}
7817c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7827c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7837c478bd9Sstevel@tonic-gate		n1 = r[1]
7847c478bd9Sstevel@tonic-gate		n2 = r[2]
7857c478bd9Sstevel@tonic-gate		final = n2
7867c478bd9Sstevel@tonic-gate		d2 = 0;
7877c478bd9Sstevel@tonic-gate		if (n == 1) {
7887c478bd9Sstevel@tonic-gate			final = n1
789daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7907c478bd9Sstevel@tonic-gate		} else {
7917c478bd9Sstevel@tonic-gate			d2 = n2 - n1
792daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7937c478bd9Sstevel@tonic-gate		}
7947c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
7957c478bd9Sstevel@tonic-gate		n1 = r[1]
7967c478bd9Sstevel@tonic-gate		n2 = r[2]
7977c478bd9Sstevel@tonic-gate		if (m > 1) {
7987c478bd9Sstevel@tonic-gate			d1  = n2 - n1
7997c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8007c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8017c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8027c478bd9Sstevel@tonic-gate			}
8037c478bd9Sstevel@tonic-gate		}
8047c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8057c478bd9Sstevel@tonic-gate		next
8067c478bd9Sstevel@tonic-gate	}
8077c478bd9Sstevel@tonic-gate	}
808daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8097c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8107c478bd9Sstevel@tonic-gate
811daaffb31Sdp	#
812cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
813daaffb31Sdp	#
814cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8157c478bd9Sstevel@tonic-gate
816cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8177c478bd9Sstevel@tonic-gate
818daaffb31Sdp	#
819daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
820daaffb31Sdp	#
821daaffb31Sdp	print "$HTML<head>$STDHEAD"
822cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
823daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
824daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
825daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
826daaffb31Sdp	print "<table><tr valign=\"top\">"
827daaffb31Sdp	print "<td><pre>"
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8307c478bd9Sstevel@tonic-gate
831daaffb31Sdp	print "</pre></td><td><pre>"
8327c478bd9Sstevel@tonic-gate
8337c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8347c478bd9Sstevel@tonic-gate
835daaffb31Sdp	print "</pre></td>"
836daaffb31Sdp	print "</tr></table>"
837daaffb31Sdp	print "</body></html>"
8387c478bd9Sstevel@tonic-gate
839daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
840daaffb31Sdp	    "$COMMENT"
8417c478bd9Sstevel@tonic-gate}
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate
844daaffb31Sdp#
845daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
846daaffb31Sdp#
847daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
848daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
849daaffb31Sdp# and then emit the main frame.  Content is placed into:
850daaffb31Sdp#
851daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
852daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
853daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
854daaffb31Sdp#
855daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
856daaffb31Sdp#
8577c478bd9Sstevel@tonic-gatefunction framed_sdiff
8587c478bd9Sstevel@tonic-gate{
8597c478bd9Sstevel@tonic-gate	typeset TNAME=$1
860daaffb31Sdp	typeset TPATH=$2
861daaffb31Sdp	typeset lhsfile=$3
862daaffb31Sdp	typeset rhsfile=$4
863daaffb31Sdp	typeset comments=$5
8647c478bd9Sstevel@tonic-gate	typeset RTOP
865daaffb31Sdp
8667c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
867daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
868daaffb31Sdp
869daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
870daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
871daaffb31Sdp
872daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8738b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8747c478bd9Sstevel@tonic-gate	    </head>
875daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
876cac38512Smjnelson	    <a name="0"></a>
877cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
878daaffb31Sdp	EOF
879daaffb31Sdp
880daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
881daaffb31Sdp
882daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
883daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
884daaffb31Sdp
885daaffb31Sdp	close='</body></html>'
886daaffb31Sdp
887daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
888daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
889daaffb31Sdp
890daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
891daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
892daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
893daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
894daaffb31Sdp	  <frameset rows="*,60">
895daaffb31Sdp	    <frameset cols="50%,50%">
896cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
897cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
898daaffb31Sdp	    </frameset>
8998b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
900cac38512Smjnelson	   marginheight="0" name="nav"></frame>
901daaffb31Sdp	  <noframes>
902daaffb31Sdp            <body id="SUNWwebrev">
903daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9047c478bd9Sstevel@tonic-gate	      and has the feature enabled.
905daaffb31Sdp            </body>
906daaffb31Sdp	  </noframes>
907daaffb31Sdp	  </frameset>
9087c478bd9Sstevel@tonic-gate	</html>
9097c478bd9Sstevel@tonic-gate	EOF
9107c478bd9Sstevel@tonic-gate}
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate
913daaffb31Sdp#
914daaffb31Sdp# fix_postscript
915daaffb31Sdp#
916daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
917daaffb31Sdp#	- removing all extraneous headers/trailers
918daaffb31Sdp#	- making the page numbers right
919daaffb31Sdp#	- removing pages devoid of contents which confuse some
920daaffb31Sdp#	  postscript readers.
921daaffb31Sdp#
922daaffb31Sdp# From Casper.
923daaffb31Sdp#
924daaffb31Sdpfunction fix_postscript
9257c478bd9Sstevel@tonic-gate{
926daaffb31Sdp	infile=$1
9277c478bd9Sstevel@tonic-gate
928daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9297c478bd9Sstevel@tonic-gate
930daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
931daaffb31Sdp	print "%%Orientation: Landscape\n";
9327c478bd9Sstevel@tonic-gate
933daaffb31Sdp	$pno = 0;
934daaffb31Sdp	$doprint = 1;
935daaffb31Sdp
936daaffb31Sdp	$page = "";
937daaffb31Sdp
938daaffb31Sdp	while (<>) {
939daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
940daaffb31Sdp
941daaffb31Sdp		if (/^%%Page:/) {
942daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
943daaffb31Sdp				# Header or single page containing text
944daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
945daaffb31Sdp				print $page;
946daaffb31Sdp				$pno++;
947daaffb31Sdp			} else {
948daaffb31Sdp				# Empty page, skip it.
9497c478bd9Sstevel@tonic-gate			}
950daaffb31Sdp			$page = "";
951daaffb31Sdp			$doprint = 1;
9527c478bd9Sstevel@tonic-gate			next;
9537c478bd9Sstevel@tonic-gate		}
9547c478bd9Sstevel@tonic-gate
955daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
956daaffb31Sdp		# %%Page of the next
957daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
958daaffb31Sdp		$page .= $_ if ($doprint);
9597c478bd9Sstevel@tonic-gate	}
9607c478bd9Sstevel@tonic-gate
961daaffb31Sdp	if ($page =~ /\)S/) {
962daaffb31Sdp		print "%%Page: ? $pno\n";
963daaffb31Sdp		print $page;
964daaffb31Sdp	} else {
965daaffb31Sdp		$pno--;
966daaffb31Sdp	}
967daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
968daaffb31SdpEOF
969daaffb31Sdp
97014983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
971daaffb31Sdp}
972daaffb31Sdp
973daaffb31Sdp
974daaffb31Sdp#
975daaffb31Sdp# input_cmd | insert_anchors | output_cmd
976daaffb31Sdp#
9777c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
978daaffb31Sdp# anchors.  These are used to drive the frames version of the
9797c478bd9Sstevel@tonic-gate# sdiffs output.
9807c478bd9Sstevel@tonic-gate#
9817c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9827c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9837c478bd9Sstevel@tonic-gate#
984daaffb31Sdp# The script detects changed lines as any line that has a "<span
985daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
986daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
9877c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
9887c478bd9Sstevel@tonic-gate# deleted.
9897c478bd9Sstevel@tonic-gate#
990daaffb31Sdpfunction insert_anchors
991daaffb31Sdp{
992cdf0c1d5Smjnelson	$AWK '
9937c478bd9Sstevel@tonic-gate	function ia() {
994daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
9957c478bd9Sstevel@tonic-gate	}
996daaffb31Sdp
9977c478bd9Sstevel@tonic-gate	BEGIN {
998daaffb31Sdp		anc=1;
9997c478bd9Sstevel@tonic-gate		inblock=1;
1000daaffb31Sdp		printf "<pre>\n";
10017c478bd9Sstevel@tonic-gate	}
1002daaffb31Sdp	NF == 0 || /^<span class=/ {
10037c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10047c478bd9Sstevel@tonic-gate			ia();
10057c478bd9Sstevel@tonic-gate			inblock=1;
10067c478bd9Sstevel@tonic-gate		}
10077c478bd9Sstevel@tonic-gate		print;
10087c478bd9Sstevel@tonic-gate		next;
10097c478bd9Sstevel@tonic-gate	}
10107c478bd9Sstevel@tonic-gate	{
10117c478bd9Sstevel@tonic-gate		inblock=0;
10127c478bd9Sstevel@tonic-gate		print;
10137c478bd9Sstevel@tonic-gate	}
10147c478bd9Sstevel@tonic-gate	END {
10157c478bd9Sstevel@tonic-gate		ia();
1016daaffb31Sdp
1017daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1018daaffb31Sdp		printf "--- EOF ---</b>"
10197c478bd9Sstevel@tonic-gate		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1020daaffb31Sdp		printf "</pre>"
1021daaffb31Sdp		printf "<form name=\"eof\">";
1022cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1023cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1024daaffb31Sdp		printf "</form>";
10257c478bd9Sstevel@tonic-gate	}
10267c478bd9Sstevel@tonic-gate	' $1
10277c478bd9Sstevel@tonic-gate}
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate
1030daaffb31Sdp#
1031daaffb31Sdp# relative_dir
1032daaffb31Sdp#
1033daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1034daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1035daaffb31Sdp# this function would print "../../../../".
1036daaffb31Sdp#
1037daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1038daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1039daaffb31Sdp# is not relocatable.
1040daaffb31Sdp#
1041daaffb31Sdpfunction relative_dir
10427c478bd9Sstevel@tonic-gate{
1043daaffb31Sdp        typeset cur="${1##$2?(/)}"
10448b3b7b16SMark J. Nelson
10458b3b7b16SMark J. Nelson        #
10468b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
10478b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
10488b3b7b16SMark J. Nelson        #
10490fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1050daaffb31Sdp                # Should never happen.
105114983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1052daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1053daaffb31Sdp                print -u2 "will not be relocatable!"
1054daaffb31Sdp                print $2
1055daaffb31Sdp                return
1056daaffb31Sdp        fi
1057daaffb31Sdp
10588b3b7b16SMark J. Nelson	#
10598b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
10608b3b7b16SMark J. Nelson	#
10618b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
10628b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
10638b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
10648b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
10658b3b7b16SMark J. Nelson	#    the end of a relative path.
10668b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
10678b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
10688b3b7b16SMark J. Nelson	#    level of relative separation.
10698b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
10708b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
10718b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
10728b3b7b16SMark J. Nelson	#
10730fd2682eSMark J. Nelson	print $cur | $SED -e '{
10748b3b7b16SMark J. Nelson		s:^\./*::
10758b3b7b16SMark J. Nelson		s:/$::
10768b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
10770fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
10780fd2682eSMark J. Nelson	}'
10797c478bd9Sstevel@tonic-gate}
10807c478bd9Sstevel@tonic-gate
1081daaffb31Sdp#
1082daaffb31Sdp# frame_nav_js
1083daaffb31Sdp#
1084daaffb31Sdp# Emit javascript for frame navigation
1085daaffb31Sdp#
1086daaffb31Sdpfunction frame_nav_js
10877c478bd9Sstevel@tonic-gate{
10887c478bd9Sstevel@tonic-gatecat << \EOF
10897c478bd9Sstevel@tonic-gatevar myInt;
10907c478bd9Sstevel@tonic-gatevar scrolling=0;
1091daaffb31Sdpvar sfactor = 3;
10927c478bd9Sstevel@tonic-gatevar scount=10;
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gatefunction scrollByPix() {
10957c478bd9Sstevel@tonic-gate	if (scount<=0) {
10967c478bd9Sstevel@tonic-gate		sfactor*=1.2;
10977c478bd9Sstevel@tonic-gate		scount=10;
10987c478bd9Sstevel@tonic-gate	}
10997c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11007c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11017c478bd9Sstevel@tonic-gate	scount--;
11027c478bd9Sstevel@tonic-gate}
11037c478bd9Sstevel@tonic-gate
1104daaffb31Sdpfunction scrollToAnc(num) {
1105daaffb31Sdp
1106daaffb31Sdp	// Update the value of the anchor in the form which we use as
1107daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1108daaffb31Sdp	// correcting for overflow and underflow of the value and return
1109daaffb31Sdp	// us the new value.
1110daaffb31Sdp	num = setAncValue(num);
1111daaffb31Sdp
1112daaffb31Sdp	// Set location and scroll back a little to expose previous
1113daaffb31Sdp	// lines.
1114daaffb31Sdp	//
1115daaffb31Sdp	// Note that this could be improved: it is possible although
1116daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1117daaffb31Sdp	// scroll to that location directly.
1118daaffb31Sdp	//
11197c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11207c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1121daaffb31Sdp
11227c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11237c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11247c478bd9Sstevel@tonic-gate}
11257c478bd9Sstevel@tonic-gate
1126daaffb31Sdpfunction getAncValue()
1127daaffb31Sdp{
1128daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1129daaffb31Sdp}
1130daaffb31Sdp
1131daaffb31Sdpfunction setAncValue(val)
1132daaffb31Sdp{
1133daaffb31Sdp	if (val <= 0) {
1134daaffb31Sdp		val = 0;
1135daaffb31Sdp		parent.nav.document.diff.real.value = val;
1136daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1137daaffb31Sdp		return (val);
1138daaffb31Sdp	}
1139daaffb31Sdp
1140daaffb31Sdp	//
1141daaffb31Sdp	// The way we compute the max anchor value is to stash it
1142daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1143daaffb31Sdp	// on each side, so we pluck from the left.
1144daaffb31Sdp	//
1145daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1146daaffb31Sdp	if (val < maxval) {
1147daaffb31Sdp		parent.nav.document.diff.real.value = val;
1148daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1149daaffb31Sdp		return (val);
1150daaffb31Sdp	}
1151daaffb31Sdp
1152daaffb31Sdp	// this must be: val >= maxval
1153daaffb31Sdp	val = maxval;
1154daaffb31Sdp	parent.nav.document.diff.real.value = val;
1155daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1156daaffb31Sdp	return (val);
1157daaffb31Sdp}
1158daaffb31Sdp
11597c478bd9Sstevel@tonic-gatefunction stopScroll() {
11607c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11617c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11627c478bd9Sstevel@tonic-gate		scrolling=0;
11637c478bd9Sstevel@tonic-gate	}
11647c478bd9Sstevel@tonic-gate}
11657c478bd9Sstevel@tonic-gate
11667c478bd9Sstevel@tonic-gatefunction startScroll() {
11677c478bd9Sstevel@tonic-gate	stopScroll();
11687c478bd9Sstevel@tonic-gate	scrolling=1;
11697c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11707c478bd9Sstevel@tonic-gate}
11717c478bd9Sstevel@tonic-gate
11727c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1173daaffb31Sdp
11747c478bd9Sstevel@tonic-gate	switch (b) {
11757c478bd9Sstevel@tonic-gate	    case 1 :
1176daaffb31Sdp		scrollToAnc(-1);
11777c478bd9Sstevel@tonic-gate		break;
11787c478bd9Sstevel@tonic-gate	    case 2 :
1179daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11807c478bd9Sstevel@tonic-gate		break;
11817c478bd9Sstevel@tonic-gate	    case 3 :
11827c478bd9Sstevel@tonic-gate		sfactor=-3;
11837c478bd9Sstevel@tonic-gate		startScroll();
11847c478bd9Sstevel@tonic-gate		break;
11857c478bd9Sstevel@tonic-gate	    case 4 :
11867c478bd9Sstevel@tonic-gate		sfactor=3;
11877c478bd9Sstevel@tonic-gate		startScroll();
11887c478bd9Sstevel@tonic-gate		break;
11897c478bd9Sstevel@tonic-gate	    case 5 :
1190daaffb31Sdp		scrollToAnc(getAncValue() + 1);
11917c478bd9Sstevel@tonic-gate		break;
11927c478bd9Sstevel@tonic-gate	    case 6 :
1193daaffb31Sdp		scrollToAnc(999999);
11947c478bd9Sstevel@tonic-gate		break;
11957c478bd9Sstevel@tonic-gate	}
11967c478bd9Sstevel@tonic-gate}
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
11997c478bd9Sstevel@tonic-gate	stopScroll();
12007c478bd9Sstevel@tonic-gate}
12017c478bd9Sstevel@tonic-gate
1202daaffb31Sdpfunction keypress(ev) {
1203daaffb31Sdp	var keynum;
1204daaffb31Sdp	var keychar;
1205daaffb31Sdp
1206daaffb31Sdp	if (window.event) { // IE
1207daaffb31Sdp		keynum = ev.keyCode;
1208daaffb31Sdp	} else if (ev.which) { // non-IE
1209daaffb31Sdp		keynum = ev.which;
1210daaffb31Sdp	}
1211daaffb31Sdp
1212daaffb31Sdp	keychar = String.fromCharCode(keynum);
1213daaffb31Sdp
1214daaffb31Sdp	if (keychar == "k") {
1215daaffb31Sdp		handlePress(2);
1216daaffb31Sdp		return (0);
1217daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1218daaffb31Sdp		handlePress(5);
1219daaffb31Sdp		return (0);
1220daaffb31Sdp	}
1221daaffb31Sdp	return (1);
1222daaffb31Sdp}
1223daaffb31Sdp
12247c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1225daaffb31Sdp	val = parent.nav.document.diff.display.value;
1226daaffb31Sdp	if (val == "EOF") {
1227daaffb31Sdp		scrollToAnc(999999);
1228daaffb31Sdp		return;
1229daaffb31Sdp	}
1230daaffb31Sdp
1231daaffb31Sdp	if (val == "BOF") {
1232daaffb31Sdp		scrollToAnc(0);
1233daaffb31Sdp		return;
1234daaffb31Sdp	}
1235daaffb31Sdp
1236daaffb31Sdp        i=parseInt(val);
12377c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1238daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12397c478bd9Sstevel@tonic-gate        } else {
1240daaffb31Sdp                scrollToAnc(i);
12417c478bd9Sstevel@tonic-gate        }
12427c478bd9Sstevel@tonic-gate        return false;
12437c478bd9Sstevel@tonic-gate}
12447c478bd9Sstevel@tonic-gate
1245daaffb31SdpEOF
1246daaffb31Sdp}
1247daaffb31Sdp
1248daaffb31Sdp#
1249daaffb31Sdp# frame_navigation
1250daaffb31Sdp#
1251daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1252daaffb31Sdp#
1253daaffb31Sdpfunction frame_navigation
1254daaffb31Sdp{
1255daaffb31Sdp	print "$HTML<head>$STDHEAD"
1256daaffb31Sdp
1257daaffb31Sdp	cat << \EOF
1258daaffb31Sdp<title>Anchor Navigation</title>
1259daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1260daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1261daaffb31Sdp
1262daaffb31Sdp<style type="text/css">
1263daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1264daaffb31Sdp		    background-color: #eee; text-align: center;
1265daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1266daaffb31Sdp    div.button a { font-weight: bold; color: black }
1267daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1268daaffb31Sdp</style>
1269daaffb31SdpEOF
1270daaffb31Sdp
1271cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1272daaffb31Sdp
1273daaffb31Sdp	cat << \EOF
12747c478bd9Sstevel@tonic-gate</head>
1275daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1276daaffb31Sdp	onkeypress="keypress(event);">
12777c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12787c478bd9Sstevel@tonic-gate      <center>
1279cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12807c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12817c478bd9Sstevel@tonic-gate      </center>
12827c478bd9Sstevel@tonic-gate    </noscript>
12837c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1284daaffb31Sdp	<tr>
1285daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1286daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1287daaffb31Sdp          at right</td>
1288daaffb31Sdp	  <td align="center" valign="top" width="50%">
12897c478bd9Sstevel@tonic-gate	    <div class="button">
1290daaffb31Sdp	      <table border="0" align="center">
1291daaffb31Sdp                  <tr>
1292daaffb31Sdp		    <td>
12937c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
12947c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
12957c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
12967c478bd9Sstevel@tonic-gate			 onClick="return false;"
12977c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1298daaffb31Sdp		    <td>
12997c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13007c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13017c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13027c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1303daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1304daaffb31Sdp		    <td>
13057c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13067c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13077c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13087c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13097c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13107c478bd9Sstevel@tonic-gate		    </td></tr>
1311daaffb31Sdp
13127c478bd9Sstevel@tonic-gate		  <tr>
1313daaffb31Sdp		    <td>
13147c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13157c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13167c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13177c478bd9Sstevel@tonic-gate			 onClick="return false;"
13187c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1319daaffb31Sdp		    <td>
13207c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13217c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13227c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13237c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1324daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1325daaffb31Sdp		    <td>
13267c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13277c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13287c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13297c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13307c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1331daaffb31Sdp		  </tr>
1332daaffb31Sdp              </table>
1333daaffb31Sdp	    </div>
1334daaffb31Sdp	  </td>
13357c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1336daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1337cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1338cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13397c478bd9Sstevel@tonic-gate	    </form>
13407c478bd9Sstevel@tonic-gate	  </th>
1341daaffb31Sdp	</tr>
13427c478bd9Sstevel@tonic-gate    </table>
13437c478bd9Sstevel@tonic-gate  </body>
13447c478bd9Sstevel@tonic-gate</html>
13457c478bd9Sstevel@tonic-gateEOF
13467c478bd9Sstevel@tonic-gate}
13477c478bd9Sstevel@tonic-gate
13487c478bd9Sstevel@tonic-gate
1349daaffb31Sdp
1350daaffb31Sdp#
1351daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1352daaffb31Sdp#
1353daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1354daaffb31Sdp# context or unified diffs.
1355daaffb31Sdp#
13567c478bd9Sstevel@tonic-gatediff_to_html()
13577c478bd9Sstevel@tonic-gate{
13587c478bd9Sstevel@tonic-gate	TNAME=$1
1359daaffb31Sdp	TPATH=$2
1360daaffb31Sdp	DIFFTYPE=$3
1361daaffb31Sdp	COMMENT=$4
1362daaffb31Sdp
1363daaffb31Sdp	print "$HTML<head>$STDHEAD"
1364daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1365daaffb31Sdp
1366daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1367daaffb31Sdp		print "$UDIFFCSS"
1368daaffb31Sdp	fi
1369daaffb31Sdp
1370daaffb31Sdp	cat <<-EOF
1371daaffb31Sdp	</head>
1372daaffb31Sdp	<body id="SUNWwebrev">
1373daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1374daaffb31Sdp	<pre>$COMMENT</pre>
1375daaffb31Sdp        <pre>
1376daaffb31Sdp	EOF
13777c478bd9Sstevel@tonic-gate
1378cdf0c1d5Smjnelson	html_quote | $AWK '
1379daaffb31Sdp	/^--- new/	{ next }
1380daaffb31Sdp	/^\+\+\+ new/	{ next }
1381daaffb31Sdp	/^--- old/	{ next }
1382daaffb31Sdp	/^\*\*\* old/	{ next }
1383daaffb31Sdp	/^\*\*\*\*/	{ next }
13847c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1385cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1386daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1387daaffb31Sdp			  next}
1388daaffb31Sdp
1389cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1390daaffb31Sdp			  next}
1391daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1392daaffb31Sdp			  next}
1393daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1394daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1395daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1396daaffb31Sdp			{printf "%s\n", $0; next}
13977c478bd9Sstevel@tonic-gate	'
1398daaffb31Sdp
1399daaffb31Sdp	print "</pre></body></html>\n"
14007c478bd9Sstevel@tonic-gate}
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate
1403daaffb31Sdp#
1404daaffb31Sdp# source_to_html { new | old } <filename>
1405daaffb31Sdp#
1406daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1407daaffb31Sdp#
14087c478bd9Sstevel@tonic-gatesource_to_html()
14097c478bd9Sstevel@tonic-gate{
14107c478bd9Sstevel@tonic-gate	WHICH=$1
14117c478bd9Sstevel@tonic-gate	TNAME=$2
14127c478bd9Sstevel@tonic-gate
1413daaffb31Sdp	print "$HTML<head>$STDHEAD"
1414cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1415daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1416daaffb31Sdp	print "<pre>"
1417cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1418daaffb31Sdp	print "</pre></body></html>"
14197c478bd9Sstevel@tonic-gate}
14207c478bd9Sstevel@tonic-gate
1421daaffb31Sdp#
1422cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1423daaffb31Sdp#
1424daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1425daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1426daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1427daaffb31Sdp# delta in that list (the first delta unique to the child).
14287c478bd9Sstevel@tonic-gate#
14297c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1430daaffb31Sdp#
1431daaffb31Sdpcomments_from_teamware()
14327c478bd9Sstevel@tonic-gate{
1433daaffb31Sdp	fmt=$1
1434daaffb31Sdp	pfile=$PWS/$2
1435daaffb31Sdp	cfile=$CWS/$3
14367c478bd9Sstevel@tonic-gate
1437cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1438cdf0c1d5Smjnelson		pfile=$RWS/$2
1439cdf0c1d5Smjnelson	fi
1440cdf0c1d5Smjnelson
1441daaffb31Sdp	if [[ -f $pfile ]]; then
1442cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14437c478bd9Sstevel@tonic-gate	else
14447c478bd9Sstevel@tonic-gate		psid=1.1
14457c478bd9Sstevel@tonic-gate	fi
14467c478bd9Sstevel@tonic-gate
1447cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14487c478bd9Sstevel@tonic-gate	N=${#sids[@]}
14497c478bd9Sstevel@tonic-gate
1450daaffb31Sdp	nawkprg='
1451daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1452daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1453daaffb31Sdp		NF == 0u	{ continue }
1454daaffb31Sdp		{if (p==0) continue; print $0 }'
1455daaffb31Sdp
14567c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
14577c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14587c478bd9Sstevel@tonic-gate
1459daaffb31Sdp		if [[ $fmt == "text" ]]; then
1460cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1461cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1462daaffb31Sdp			return
1463daaffb31Sdp		fi
1464daaffb31Sdp
1465cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
14660fd2682eSMark J. Nelson		    html_quote | its2url | $AWK "$nawkprg"
14677c478bd9Sstevel@tonic-gate	fi
14687c478bd9Sstevel@tonic-gate}
14697c478bd9Sstevel@tonic-gate
1470daaffb31Sdp#
1471cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1472daaffb31Sdp#
1473cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1474cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1475cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1476cdf0c1d5Smjnelson# are turned into URLs.
1477cdf0c1d5Smjnelson#
1478cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1479daaffb31Sdp#
1480daaffb31Sdpcomments_from_wx()
14817c478bd9Sstevel@tonic-gate{
1482daaffb31Sdp	typeset fmt=$1
1483daaffb31Sdp	typeset p=$2
14847c478bd9Sstevel@tonic-gate
1485cdf0c1d5Smjnelson	comm=`$AWK '
1486daaffb31Sdp	$1 == "'$p'" {
14877c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
14887c478bd9Sstevel@tonic-gate		getline
14897c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
14907c478bd9Sstevel@tonic-gate		exit
1491daaffb31Sdp	}' < $wxfile`
1492daaffb31Sdp
1493cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1494cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1495cdf0c1d5Smjnelson	fi
1496cdf0c1d5Smjnelson
1497daaffb31Sdp	if [[ $fmt == "text" ]]; then
1498cdf0c1d5Smjnelson		print -- "$comm"
1499daaffb31Sdp		return
1500daaffb31Sdp	fi
1501daaffb31Sdp
15020fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1503cdf0c1d5Smjnelson
15047c478bd9Sstevel@tonic-gate}
15057c478bd9Sstevel@tonic-gate
15067c478bd9Sstevel@tonic-gate#
1507daaffb31Sdp# getcomments {text|html} filepath parentpath
1508daaffb31Sdp#
1509daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1510daaffb31Sdp#
1511daaffb31Sdpgetcomments()
1512daaffb31Sdp{
1513daaffb31Sdp	typeset fmt=$1
1514daaffb31Sdp	typeset p=$2
1515daaffb31Sdp	typeset pp=$3
15167c478bd9Sstevel@tonic-gate
15173df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15183df69ef3SDarren Moffat		return
15193df69ef3SDarren Moffat	fi
1520cdf0c1d5Smjnelson	#
1521cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1522cdf0c1d5Smjnelson	# will be used there, too
1523cdf0c1d5Smjnelson	#
1524daaffb31Sdp	if [[ -n $wxfile ]]; then
1525daaffb31Sdp		comments_from_wx $fmt $p
1526daaffb31Sdp	else
1527daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1528daaffb31Sdp			comments_from_teamware $fmt $pp $p
1529daaffb31Sdp		fi
1530daaffb31Sdp	fi
1531daaffb31Sdp}
1532daaffb31Sdp
1533daaffb31Sdp#
1534daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1535daaffb31Sdp#
1536daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1537daaffb31Sdp#
1538daaffb31Sdpfunction printCI
1539daaffb31Sdp{
1540daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1541daaffb31Sdp	typeset str
1542daaffb31Sdp	if (( tot == 1 )); then
1543daaffb31Sdp		str="line"
1544daaffb31Sdp	else
1545daaffb31Sdp		str="lines"
1546daaffb31Sdp	fi
1547daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1548daaffb31Sdp	    $tot $str $ins $del $mod $unc
1549daaffb31Sdp}
1550daaffb31Sdp
1551daaffb31Sdp
1552daaffb31Sdp#
1553daaffb31Sdp# difflines <oldfile> <newfile>
1554daaffb31Sdp#
1555daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1556daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1557daaffb31Sdp#
15587c478bd9Sstevel@tonic-gatefunction difflines
15597c478bd9Sstevel@tonic-gate{
1560daaffb31Sdp	integer tot mod del ins unc err
15617c478bd9Sstevel@tonic-gate	typeset filename
15627c478bd9Sstevel@tonic-gate
1563cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1564daaffb31Sdp	# Change range of lines: N,Nc
15657c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15667c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15677c478bd9Sstevel@tonic-gate		if (n != 2) {
15687c478bd9Sstevel@tonic-gate		    error=2
15697c478bd9Sstevel@tonic-gate		    exit;
15707c478bd9Sstevel@tonic-gate		}
1571daaffb31Sdp		#
1572daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1573daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1574daaffb31Sdp		#
15757c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1576daaffb31Sdp
1577daaffb31Sdp		#
1578daaffb31Sdp		# Now count replacement lines: each represents a change instead
1579daaffb31Sdp		# of a delete, so increment c and decrement r.
1580daaffb31Sdp		#
15817c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15827c478bd9Sstevel@tonic-gate			c++;
15837c478bd9Sstevel@tonic-gate			r--;
15847c478bd9Sstevel@tonic-gate		}
1585daaffb31Sdp		#
1586daaffb31Sdp		# If there were more replacement lines than original lines,
1587daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1588daaffb31Sdp		# but there are r changes that should be counted as adds, and
1589daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1590daaffb31Sdp		#
15917c478bd9Sstevel@tonic-gate		if (r < 0) {
15927c478bd9Sstevel@tonic-gate			a-=r;
15937c478bd9Sstevel@tonic-gate			c+=r;
15947c478bd9Sstevel@tonic-gate		}
1595daaffb31Sdp
1596daaffb31Sdp		#
1597daaffb31Sdp		# If there were more original lines than replacement lines, then
1598daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1599daaffb31Sdp		#
16007c478bd9Sstevel@tonic-gate		if (r > 0) {
16017c478bd9Sstevel@tonic-gate			d+=r;
16027c478bd9Sstevel@tonic-gate		}
16037c478bd9Sstevel@tonic-gate		next;
16047c478bd9Sstevel@tonic-gate	}
16057c478bd9Sstevel@tonic-gate
1606daaffb31Sdp	# Change lines: Nc
16077c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1608daaffb31Sdp		# The first line is a replacement; any more are additions.
16097c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16107c478bd9Sstevel@tonic-gate			c++;
16117c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16127c478bd9Sstevel@tonic-gate		}
16137c478bd9Sstevel@tonic-gate		next;
16147c478bd9Sstevel@tonic-gate	}
16157c478bd9Sstevel@tonic-gate
1616daaffb31Sdp	# Add lines: both Na and N,Na
16177c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16187c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16197c478bd9Sstevel@tonic-gate		next;
16207c478bd9Sstevel@tonic-gate	}
16217c478bd9Sstevel@tonic-gate
1622daaffb31Sdp	# Delete range of lines: N,Nd
16237c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16247c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16257c478bd9Sstevel@tonic-gate		if (n != 2) {
16267c478bd9Sstevel@tonic-gate			error=2
16277c478bd9Sstevel@tonic-gate			exit;
16287c478bd9Sstevel@tonic-gate		}
1629daaffb31Sdp		#
1630daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1631daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1632daaffb31Sdp		#
16337c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16347c478bd9Sstevel@tonic-gate		d+=r;
16357c478bd9Sstevel@tonic-gate		next;
16367c478bd9Sstevel@tonic-gate	}
16377c478bd9Sstevel@tonic-gate
1638daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16397c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16407c478bd9Sstevel@tonic-gate
1641daaffb31Sdp	# Should not get here!
16427c478bd9Sstevel@tonic-gate	{
16437c478bd9Sstevel@tonic-gate		error=1;
16447c478bd9Sstevel@tonic-gate		exit;
16457c478bd9Sstevel@tonic-gate	}
16467c478bd9Sstevel@tonic-gate
1647daaffb31Sdp	# Finish off - print results
16487c478bd9Sstevel@tonic-gate	END {
1649daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16507c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16517c478bd9Sstevel@tonic-gate	}' )
16527c478bd9Sstevel@tonic-gate
1653cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16547c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1655daaffb31Sdp		print "Unexpected Error occurred reading" \
1656daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1657daaffb31Sdp		return
1658daaffb31Sdp	fi
1659daaffb31Sdp
16607c478bd9Sstevel@tonic-gate	# Accumulate totals
16617c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1662daaffb31Sdp	(( TMOD += mod ))
16637c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16647c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16657c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1666cdf0c1d5Smjnelson	unc=`wc -l < $1`
16677c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1668daaffb31Sdp		(( unc -= del + mod ))
16697c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16707c478bd9Sstevel@tonic-gate	fi
16717c478bd9Sstevel@tonic-gate	# print summary
1672daaffb31Sdp	print "<span class=\"lineschanged\">"
1673daaffb31Sdp	printCI $tot $ins $del $mod $unc
1674daaffb31Sdp	print "</span>"
16757c478bd9Sstevel@tonic-gate}
16767c478bd9Sstevel@tonic-gate
1677daaffb31Sdp
16787c478bd9Sstevel@tonic-gate#
1679daaffb31Sdp# flist_from_wx
1680daaffb31Sdp#
1681daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1682daaffb31Sdp# Sets the global 'wxfile' variable.
1683daaffb31Sdp#
1684daaffb31Sdpfunction flist_from_wx
16857c478bd9Sstevel@tonic-gate{
1686daaffb31Sdp	typeset argfile=$1
1687daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1688daaffb31Sdp		#
1689daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1690daaffb31Sdp		# because the webrev does a "cd" later on.
1691daaffb31Sdp		#
1692daaffb31Sdp		wxfile=$PWD/$argfile
16937c478bd9Sstevel@tonic-gate	else
1694daaffb31Sdp		wxfile=$argfile
16957c478bd9Sstevel@tonic-gate	fi
16967c478bd9Sstevel@tonic-gate
1697cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
16987c478bd9Sstevel@tonic-gate	  while (getline) {
16997c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
17007c478bd9Sstevel@tonic-gate		if (c > 0) print
17017c478bd9Sstevel@tonic-gate	  }
1702daaffb31Sdp	}' $wxfile > $FLIST
17037c478bd9Sstevel@tonic-gate
1704daaffb31Sdp	print " Done."
1705daaffb31Sdp}
17067c478bd9Sstevel@tonic-gate
1707daaffb31Sdp#
1708daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1709daaffb31Sdp#
1710daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1711daaffb31Sdp# names may come from the "update/create" messages and others from the
1712daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1713daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1714daaffb31Sdp# -n as well, but remove them if they are already defined.
1715daaffb31Sdp#
1716daaffb31Sdpfunction flist_from_teamware
1717daaffb31Sdp{
1718cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1719daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1720daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1721daaffb31Sdp			    "valid teamware workspace"
17227c478bd9Sstevel@tonic-gate			exit 1
17237c478bd9Sstevel@tonic-gate		fi
1724daaffb31Sdp		parent_args="-p $codemgr_parent"
17257c478bd9Sstevel@tonic-gate	fi
17267c478bd9Sstevel@tonic-gate
1727daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17287c478bd9Sstevel@tonic-gate
1729daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1730cdf0c1d5Smjnelson	    $AWK '
1731daaffb31Sdp		/^update:|^create:/	{print $2}
1732daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1733daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1734daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1735daaffb31Sdp		NF == 0			{p=0 ; continue}
1736daaffb31Sdp		/^rename/		{old=$3}
1737daaffb31Sdp		$1 == "to:"		{print $2, old}
1738daaffb31Sdp		/^"/			{continue}
1739daaffb31Sdp		p == 1			{print $1}' |
1740daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17417c478bd9Sstevel@tonic-gate
1742daaffb31Sdp	print " Done."
1743daaffb31Sdp}
1744daaffb31Sdp
1745cdf0c1d5Smjnelson#
1746cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1747cdf0c1d5Smjnelson#
1748cdf0c1d5Smjnelsonfunction hg_active_wxfile
1749cdf0c1d5Smjnelson{
1750cdf0c1d5Smjnelson	typeset child=$1
1751cdf0c1d5Smjnelson	typeset parent=$2
1752cdf0c1d5Smjnelson
1753cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17549a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1755cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1756cdf0c1d5Smjnelson}
1757cdf0c1d5Smjnelson
1758cdf0c1d5Smjnelson#
1759cdf0c1d5Smjnelson# flist_from_mercurial
1760cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1761cdf0c1d5Smjnelson# flist_from_wx
1762cdf0c1d5Smjnelson#
1763cdf0c1d5Smjnelsonfunction flist_from_mercurial
1764cdf0c1d5Smjnelson{
1765cdf0c1d5Smjnelson	typeset child=$1
1766cdf0c1d5Smjnelson	typeset parent=$2
1767cdf0c1d5Smjnelson
1768cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1769cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1770cdf0c1d5Smjnelson		print		# Blank line for the \c above
1771cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1772cdf0c1d5Smjnelson		exit 1
1773cdf0c1d5Smjnelson	fi
1774cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1775cdf0c1d5Smjnelson
1776cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1777cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1778cdf0c1d5Smjnelson}
1779cdf0c1d5Smjnelson
1780cdf0c1d5Smjnelson#
1781cdf0c1d5Smjnelson# flist_from_subversion
1782cdf0c1d5Smjnelson#
1783cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1784cdf0c1d5Smjnelson#
1785cdf0c1d5Smjnelsonfunction flist_from_subversion
1786cdf0c1d5Smjnelson{
1787cdf0c1d5Smjnelson	CWS=$1
1788cdf0c1d5Smjnelson	OLDPWD=$2
1789cdf0c1d5Smjnelson
1790cdf0c1d5Smjnelson	cd $CWS
1791cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1792cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1793cdf0c1d5Smjnelson	print -u2 " Done."
1794cdf0c1d5Smjnelson	cd $OLDPWD
1795cdf0c1d5Smjnelson}
1796cdf0c1d5Smjnelson
1797daaffb31Sdpfunction env_from_flist
1798daaffb31Sdp{
1799daaffb31Sdp	[[ -r $FLIST ]] || return
1800daaffb31Sdp
1801daaffb31Sdp	#
1802daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1803daaffb31Sdp	# list.  Then copy those into our local versions of those
1804daaffb31Sdp	# variables if they have not been set already.
1805daaffb31Sdp	#
1806b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18077c478bd9Sstevel@tonic-gate
1808cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1809cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1810cdf0c1d5Smjnelson		export CODEMGR_WS
1811cdf0c1d5Smjnelson	fi
18127c478bd9Sstevel@tonic-gate
1813daaffb31Sdp	#
1814daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1815daaffb31Sdp	#
1816cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1817daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1818cdf0c1d5Smjnelson		export CODEMGR_PARENT
1819daaffb31Sdp	fi
1820daaffb31Sdp}
1821daaffb31Sdp
182214983201Sdpfunction look_for_prog
182314983201Sdp{
182414983201Sdp	typeset path
182514983201Sdp	typeset ppath
182614983201Sdp	typeset progname=$1
182714983201Sdp
182814983201Sdp	ppath=$PATH
182914983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
183014983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1831cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
183214983201Sdp
183314983201Sdp	PATH=$ppath prog=`whence $progname`
183414983201Sdp	if [[ -n $prog ]]; then
183514983201Sdp		print $prog
183614983201Sdp	fi
183714983201Sdp}
183814983201Sdp
1839cdf0c1d5Smjnelsonfunction get_file_mode
1840cdf0c1d5Smjnelson{
1841cdf0c1d5Smjnelson	$PERL -e '
1842cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1843cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1844cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1845cdf0c1d5Smjnelson			exit 0;
1846cdf0c1d5Smjnelson		} else {
1847cdf0c1d5Smjnelson			exit 1;
1848cdf0c1d5Smjnelson		}
1849cdf0c1d5Smjnelson	    ' $1
1850cdf0c1d5Smjnelson}
1851cdf0c1d5Smjnelson
1852cdf0c1d5Smjnelsonfunction build_old_new_teamware
1853cdf0c1d5Smjnelson{
1854cdf0c1d5Smjnelson	typeset olddir="$1"
1855cdf0c1d5Smjnelson	typeset newdir="$2"
1856cdf0c1d5Smjnelson
1857cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1858cdf0c1d5Smjnelson	# get a readonly copy.
1859cdf0c1d5Smjnelson
1860cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1861cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1862cdf0c1d5Smjnelson	fi
1863cdf0c1d5Smjnelson
1864cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1865cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1866cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1867cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1868cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1869cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1870cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1871cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1872cdf0c1d5Smjnelson	# permissions that would result after check in.
1873cdf0c1d5Smjnelson
1874cdf0c1d5Smjnelson	#
1875cdf0c1d5Smjnelson	# Snag new version of file.
1876cdf0c1d5Smjnelson	#
1877cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1878cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1879cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1880cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1881cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1882cdf0c1d5Smjnelson	fi
1883cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1884cdf0c1d5Smjnelson
1885cdf0c1d5Smjnelson	#
1886cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1887cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1888cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1889cdf0c1d5Smjnelson	#
1890cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1891cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1892cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1893cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1894cdf0c1d5Smjnelson		# the old file.
1895cdf0c1d5Smjnelson
1896cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1897cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1898cdf0c1d5Smjnelson	else
1899cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1900cdf0c1d5Smjnelson			real_parent=$PWS
1901cdf0c1d5Smjnelson		else
1902cdf0c1d5Smjnelson			real_parent=$RWS
1903cdf0c1d5Smjnelson		fi
1904cdf0c1d5Smjnelson
1905cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1906cdf0c1d5Smjnelson
1907cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1908cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1909cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1910cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1911cdf0c1d5Smjnelson			else
1912cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1913cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1914cdf0c1d5Smjnelson			fi
1915cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1916cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1917cdf0c1d5Smjnelson		fi
1918cdf0c1d5Smjnelson	fi
1919cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1920cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1921cdf0c1d5Smjnelson	fi
1922cdf0c1d5Smjnelson}
1923cdf0c1d5Smjnelson
1924cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1925cdf0c1d5Smjnelson{
1926cdf0c1d5Smjnelson	typeset olddir="$1"
1927cdf0c1d5Smjnelson	typeset newdir="$2"
1928cdf0c1d5Smjnelson	typeset old_mode=
1929cdf0c1d5Smjnelson	typeset new_mode=
1930cdf0c1d5Smjnelson	typeset file
1931cdf0c1d5Smjnelson
1932cdf0c1d5Smjnelson	#
1933cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1934cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1935cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1936cdf0c1d5Smjnelson	#
1937cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1938cdf0c1d5Smjnelson		file="$PF"
1939cdf0c1d5Smjnelson	else
1940cdf0c1d5Smjnelson		file="$PDIR/$PF"
1941cdf0c1d5Smjnelson	fi
1942b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
1943cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1944b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1945cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1946cdf0c1d5Smjnelson
1947cdf0c1d5Smjnelson	#
1948cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1949cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1950cdf0c1d5Smjnelson	#
1951cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1952cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1953cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1954cdf0c1d5Smjnelson			new_mode=755
1955cdf0c1d5Smjnelson		else
1956cdf0c1d5Smjnelson			new_mode=644
1957cdf0c1d5Smjnelson		fi
1958cdf0c1d5Smjnelson	fi
1959cdf0c1d5Smjnelson
1960cdf0c1d5Smjnelson	#
1961cdf0c1d5Smjnelson	# new version of the file.
1962cdf0c1d5Smjnelson	#
1963cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1964cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1965cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1966cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1967cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1968cdf0c1d5Smjnelson		else
1969cdf0c1d5Smjnelson			# should never happen
1970cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1971cdf0c1d5Smjnelson		fi
1972cdf0c1d5Smjnelson	fi
1973cdf0c1d5Smjnelson
1974cdf0c1d5Smjnelson	#
1975cdf0c1d5Smjnelson	# parent's version of the file
1976cdf0c1d5Smjnelson	#
1977cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1978cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1979cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1980cdf0c1d5Smjnelson	#
1981cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1982cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1983cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1984cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1985cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1986cdf0c1d5Smjnelson
198702d26c39SVladimir Kotal		if (( $? != 0 )); then
1988cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1989cdf0c1d5Smjnelson		else
1990cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1991cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1992cdf0c1d5Smjnelson			else
1993cdf0c1d5Smjnelson				# should never happen
1994cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1995cdf0c1d5Smjnelson			fi
1996cdf0c1d5Smjnelson		fi
1997cdf0c1d5Smjnelson	fi
1998cdf0c1d5Smjnelson}
1999cdf0c1d5Smjnelson
2000cdf0c1d5Smjnelsonfunction build_old_new_subversion
2001cdf0c1d5Smjnelson{
2002cdf0c1d5Smjnelson	typeset olddir="$1"
2003cdf0c1d5Smjnelson	typeset newdir="$2"
2004cdf0c1d5Smjnelson
2005cdf0c1d5Smjnelson	# Snag new version of file.
2006cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2007cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2008cdf0c1d5Smjnelson
2009cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2010cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2011cdf0c1d5Smjnelson	else
2012cdf0c1d5Smjnelson		# Get the parent's version of the file.
2013cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2014cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2015cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2016cdf0c1d5Smjnelson		fi
2017cdf0c1d5Smjnelson	fi
2018cdf0c1d5Smjnelson}
2019cdf0c1d5Smjnelson
2020cdf0c1d5Smjnelsonfunction build_old_new_unknown
2021cdf0c1d5Smjnelson{
2022cdf0c1d5Smjnelson	typeset olddir="$1"
2023cdf0c1d5Smjnelson	typeset newdir="$2"
2024cdf0c1d5Smjnelson
2025cdf0c1d5Smjnelson	#
2026cdf0c1d5Smjnelson	# Snag new version of file.
2027cdf0c1d5Smjnelson	#
2028cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2029cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2030cdf0c1d5Smjnelson
2031cdf0c1d5Smjnelson	#
2032cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2033cdf0c1d5Smjnelson	#
2034cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2035cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2036cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2037cdf0c1d5Smjnelson	fi
2038cdf0c1d5Smjnelson}
2039cdf0c1d5Smjnelson
2040cdf0c1d5Smjnelsonfunction build_old_new
2041cdf0c1d5Smjnelson{
2042cdf0c1d5Smjnelson	typeset WDIR=$1
2043cdf0c1d5Smjnelson	typeset PWS=$2
2044cdf0c1d5Smjnelson	typeset PDIR=$3
2045cdf0c1d5Smjnelson	typeset PF=$4
2046cdf0c1d5Smjnelson	typeset CWS=$5
2047cdf0c1d5Smjnelson	typeset DIR=$6
2048cdf0c1d5Smjnelson	typeset F=$7
2049cdf0c1d5Smjnelson
2050cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2051cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2052cdf0c1d5Smjnelson
2053cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2054cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2055cdf0c1d5Smjnelson
2056cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2057cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
2058cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
2059cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
2060cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2061cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2062cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2063cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2064cdf0c1d5Smjnelson	fi
2065cdf0c1d5Smjnelson
2066cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2067cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2068cdf0c1d5Smjnelson		return 1
2069cdf0c1d5Smjnelson	fi
2070cdf0c1d5Smjnelson	return 0
2071cdf0c1d5Smjnelson}
2072cdf0c1d5Smjnelson
2073cdf0c1d5Smjnelson
2074daaffb31Sdp#
2075daaffb31Sdp# Usage message.
2076daaffb31Sdp#
2077daaffb31Sdpfunction usage
2078daaffb31Sdp{
2079daaffb31Sdp	print 'Usage:\twebrev [common-options]
2080daaffb31Sdp	webrev [common-options] ( <file> | - )
2081daaffb31Sdp	webrev [common-options] -w <wx file>
2082daaffb31Sdp
2083daaffb31SdpOptions:
20840fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2085ba44d8a2SVladimir Kotal	-D: delete remote webrev
2086daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
20870fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2088ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2089ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2090daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2091daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
209202d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
209302d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2094daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2095daaffb31Sdp
2096daaffb31SdpEnvironment:
2097daaffb31Sdp	WDIR: Control the output directory.
2098ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2099daaffb31Sdp
2100cdf0c1d5SmjnelsonSCM Specific Options:
2101cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
2102cdf0c1d5Smjnelson
2103daaffb31SdpSCM Environment:
2104cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2105cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2106daaffb31Sdp'
2107daaffb31Sdp
2108daaffb31Sdp	exit 2
2109daaffb31Sdp}
2110daaffb31Sdp
2111daaffb31Sdp#
2112daaffb31Sdp#
2113daaffb31Sdp# Main program starts here
2114daaffb31Sdp#
2115daaffb31Sdp#
2116daaffb31Sdp
2117daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2118daaffb31Sdp
2119daaffb31Sdpset +o noclobber
2120daaffb31Sdp
2121cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
2122cdf0c1d5Smjnelson
212314983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
212414983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2125cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2126cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
212714983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
212814983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
212914983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
213002d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2131cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2132cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2133cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2134cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
213502d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2136b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
213702d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2138e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort`
213902d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
214002d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2141ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2142cdf0c1d5Smjnelson
2143ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2144ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2145ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
214614983201Sdp
214714983201Sdpif [[ ! -x $PERL ]]; then
214814983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
214914983201Sdp	exit 1
2150daaffb31Sdpfi
215114983201Sdp
2152cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2153cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2154cdf0c1d5Smjnelson	exit 1
2155cdf0c1d5Smjnelsonfi
2156cdf0c1d5Smjnelson
215714983201Sdp#
215814983201Sdp# These aren't fatal, but we want to note them to the user.
215914983201Sdp# We don't warn on the absence of 'wx' until later when we've
216014983201Sdp# determined that we actually need to try to invoke it.
216114983201Sdp#
216214983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
216314983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
216414983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2165daaffb31Sdp
2166daaffb31Sdp# Declare global total counters.
2167daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2168daaffb31Sdp
2169ba44d8a2SVladimir Kotal# default remote host for upload/delete
2170ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2171b0088928SVladimir Kotal# prefixes for upload targets
2172b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2173b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2174ba44d8a2SVladimir Kotal
21750fd2682eSMark J. NelsonCflag=
2176ba44d8a2SVladimir KotalDflag=
217714983201Sdpflist_mode=
217814983201Sdpflist_file=
2179daaffb31Sdpiflag=
21800fd2682eSMark J. NelsonIflag=
218102d26c39SVladimir Kotallflag=
218202d26c39SVladimir KotalNflag=
218302d26c39SVladimir Kotalnflag=
218402d26c39SVladimir KotalOflag=
2185daaffb31Sdpoflag=
2186daaffb31Sdppflag=
218702d26c39SVladimir Kotaltflag=
218802d26c39SVladimir Kotaluflag=
218902d26c39SVladimir KotalUflag=
2190daaffb31Sdpwflag=
219102d26c39SVladimir Kotalremote_target=
2192ba44d8a2SVladimir Kotal
2193ba44d8a2SVladimir Kotal#
2194ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2195ba44d8a2SVladimir Kotal#	with usr/src/tools/onbld/hgext/cdm.py
2196ba44d8a2SVladimir Kotal#
219725cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
2198daaffb31Sdpdo
2199daaffb31Sdp	case $opt in
22000fd2682eSMark J. Nelson	C)	Cflag=1
22010fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
22020fd2682eSMark J. Nelson
2203ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2204ba44d8a2SVladimir Kotal
2205daaffb31Sdp	i)	iflag=1
2206daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2207daaffb31Sdp
22080fd2682eSMark J. Nelson	I)	Iflag=1
22090fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
22100fd2682eSMark J. Nelson
2211daaffb31Sdp	#
2212daaffb31Sdp	# If -l has been specified, we need to abort further options
2213daaffb31Sdp	# processing, because subsequent arguments are going to be
2214daaffb31Sdp	# arguments to 'putback -n'.
2215daaffb31Sdp	#
2216daaffb31Sdp	l)	lflag=1
2217daaffb31Sdp		break;;
2218daaffb31Sdp
221902d26c39SVladimir Kotal	N)	Nflag=1;;
222002d26c39SVladimir Kotal
222102d26c39SVladimir Kotal	n)	nflag=1;;
2222daaffb31Sdp
2223daaffb31Sdp	O)	Oflag=1;;
2224daaffb31Sdp
222502d26c39SVladimir Kotal	o)	oflag=1
22269d3952abSVladimir Kotal		# Strip the trailing slash to correctly form remote target.
22279d3952abSVladimir Kotal		WDIR=${OPTARG%/};;
222802d26c39SVladimir Kotal
222902d26c39SVladimir Kotal	p)	pflag=1
223002d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
223102d26c39SVladimir Kotal
223202d26c39SVladimir Kotal	t)	tflag=1
223302d26c39SVladimir Kotal		remote_target=$OPTARG;;
223402d26c39SVladimir Kotal
223502d26c39SVladimir Kotal	U)	Uflag=1;;
223602d26c39SVladimir Kotal
223702d26c39SVladimir Kotal	w)	wflag=1;;
22383df69ef3SDarren Moffat
2239daaffb31Sdp	?)	usage;;
2240daaffb31Sdp	esac
2241daaffb31Sdpdone
2242daaffb31Sdp
2243daaffb31SdpFLIST=/tmp/$$.flist
2244daaffb31Sdp
2245daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2246daaffb31Sdp	usage
2247daaffb31Sdpfi
2248daaffb31Sdp
224902d26c39SVladimir Kotal# more sanity checking
225002d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2251ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2252ba44d8a2SVladimir Kotal	    "without -U"
225302d26c39SVladimir Kotal	exit 1
225402d26c39SVladimir Kotalfi
225502d26c39SVladimir Kotal
2256ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2257ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
225802d26c39SVladimir Kotal	exit 1
225902d26c39SVladimir Kotalfi
226002d26c39SVladimir Kotal
2261daaffb31Sdp#
22622d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume
22632d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name
22642d9224a3SMark J. Nelson# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
22652d9224a3SMark J. Nelson# logic.
22662d9224a3SMark J. Nelson#
22672d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1
22682d9224a3SMark J. Nelsonif [[ $SCM_MODE == "teamware" ]]; then
22692d9224a3SMark J. Nelson	#
22702d9224a3SMark J. Nelson	# Teamware priorities:
22712d9224a3SMark J. Nelson	# 1. CODEMGR_WS from the environment
22722d9224a3SMark J. Nelson	# 2. workspace name
22732d9224a3SMark J. Nelson	#
22742d9224a3SMark J. Nelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
22752d9224a3SMark J. Nelson	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
22762d9224a3SMark J. Nelson		print -u2 "$codemgr_ws: no such workspace"
22772d9224a3SMark J. Nelson		exit 1
22782d9224a3SMark J. Nelson	fi
22792d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
22802d9224a3SMark J. Nelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
22812d9224a3SMark J. Nelson	CODEMGR_WS=$codemgr_ws
22822d9224a3SMark J. Nelson	CWS=$codemgr_ws
22832d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "mercurial" ]]; then
22842d9224a3SMark J. Nelson	#
22852d9224a3SMark J. Nelson	# Mercurial priorities:
22862d9224a3SMark J. Nelson	# 1. hg root from CODEMGR_WS environment variable
2287*78add226Sjmcp	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
2288*78add226Sjmcp	#    usr/closed when we run webrev
22892d9224a3SMark J. Nelson	# 2. hg root from directory of invocation
22902d9224a3SMark J. Nelson	#
2291*78add226Sjmcp	if [[ ${PWD} =~ "usr/closed" ]]; then
2292*78add226Sjmcp		testparent=${CODEMGR_WS}/usr/closed
2293*78add226Sjmcp		# If we're in OpenSolaris mode, we enforce a minor policy:
2294*78add226Sjmcp		# help to make sure the reviewer doesn't accidentally publish
2295*78add226Sjmcp		# source which is under usr/closed
2296*78add226Sjmcp		if [[ -n "$Oflag" ]]; then
2297*78add226Sjmcp			print -u2 "OpenSolaris output not permitted with" \
2298*78add226Sjmcp			    "usr/closed changes"
2299*78add226Sjmcp			exit 1
2300*78add226Sjmcp		fi
2301*78add226Sjmcp	else
2302*78add226Sjmcp	        testparent=${CODEMGR_WS}
2303*78add226Sjmcp	fi
2304*78add226Sjmcp	[[ -z $codemgr_ws && -n $testparent ]] && \
2305*78add226Sjmcp	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
23062d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
23072d9224a3SMark J. Nelson	CWS=$codemgr_ws
23082d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then
23092d9224a3SMark J. Nelson	#
23102d9224a3SMark J. Nelson	# Subversion priorities:
23112d9224a3SMark J. Nelson	# 1. CODEMGR_WS from environment
23122d9224a3SMark J. Nelson	# 2. Relative path from current directory to SVN repository root
23132d9224a3SMark J. Nelson	#
23142d9224a3SMark J. Nelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
23152d9224a3SMark J. Nelson		CWS=$CODEMGR_WS
23162d9224a3SMark J. Nelson	else
23172d9224a3SMark J. Nelson		svn info | while read line; do
23182d9224a3SMark J. Nelson			if [[ $line == "URL: "* ]]; then
23192d9224a3SMark J. Nelson				url=${line#URL: }
23202d9224a3SMark J. Nelson			elif [[ $line == "Repository Root: "* ]]; then
23212d9224a3SMark J. Nelson				repo=${line#Repository Root: }
23222d9224a3SMark J. Nelson			fi
23232d9224a3SMark J. Nelson		done
23242d9224a3SMark J. Nelson
23252d9224a3SMark J. Nelson		rel=${url#$repo}
23262d9224a3SMark J. Nelson		CWS=${PWD%$rel}
23272d9224a3SMark J. Nelson	fi
23282d9224a3SMark J. Nelsonfi
23292d9224a3SMark J. Nelson
23302d9224a3SMark J. Nelson#
23312d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting
23322d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set.
23332d9224a3SMark J. Nelson#
23342d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then
23352d9224a3SMark J. Nelson	CWS=${CODEMGR_WS:-.}
23362d9224a3SMark J. Nelsonfi
23372d9224a3SMark J. Nelson
23382d9224a3SMark J. Nelson#
23390fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
23400fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
23410fd2682eSMark J. Nelson# ton of logic we can skip.
23420fd2682eSMark J. Nelson#
23430fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
23440fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
23450fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
23460fd2682eSMark J. Nelson#
23470fd2682eSMark J. Nelsonfor do_everything in 1; do
23480fd2682eSMark J. Nelson
23490fd2682eSMark J. Nelson# DO_EVERYTHING: break point
23500fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
23510fd2682eSMark J. Nelson	break
23520fd2682eSMark J. Nelsonfi
23530fd2682eSMark J. Nelson
23540fd2682eSMark J. Nelson#
2355daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2356daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2357daaffb31Sdp#
2358daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2359daaffb31Sdp	parent_webrev="$codemgr_parent"
2360daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2361daaffb31Sdpfi
2362daaffb31Sdp
2363daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2364daaffb31Sdp	shift $(($OPTIND - 1))
2365daaffb31Sdp
2366daaffb31Sdp	if [[ $1 == "-" ]]; then
2367daaffb31Sdp		cat > $FLIST
236814983201Sdp		flist_mode="stdin"
236914983201Sdp		flist_done=1
237014983201Sdp		shift
2371daaffb31Sdp	elif [[ -n $1 ]]; then
237214983201Sdp		if [[ ! -r $1 ]]; then
2373daaffb31Sdp			print -u2 "$1: no such file or not readable"
2374daaffb31Sdp			usage
2375daaffb31Sdp		fi
2376daaffb31Sdp		cat $1 > $FLIST
237714983201Sdp		flist_mode="file"
237814983201Sdp		flist_file=$1
237914983201Sdp		flist_done=1
238014983201Sdp		shift
2381daaffb31Sdp	else
238214983201Sdp		flist_mode="auto"
2383daaffb31Sdp	fi
2384daaffb31Sdpfi
2385daaffb31Sdp
2386daaffb31Sdp#
2387daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2388daaffb31Sdp# is in use.
2389daaffb31Sdp#
2390cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2391cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2392cdf0c1d5Smjnelson	;;
2393cdf0c1d5Smjnelsonunknown)
2394cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2395cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2396cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
23977c478bd9Sstevel@tonic-gate		exit 1
23987c478bd9Sstevel@tonic-gate	fi
2399cdf0c1d5Smjnelson	;;
2400cdf0c1d5Smjnelson*)
2401cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2402cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2403cdf0c1d5Smjnelson		exit 1
2404cdf0c1d5Smjnelson	fi
2405cdf0c1d5Smjnelson	;;
2406cdf0c1d5Smjnelsonesac
24077c478bd9Sstevel@tonic-gate
2408daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2409daaffb31Sdp
2410daaffb31Sdpif [[ -n $lflag ]]; then
2411daaffb31Sdp	#
2412daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2413daaffb31Sdp	# then generate the file list by extracting file names from a
2414daaffb31Sdp	# putback -n.
2415daaffb31Sdp	#
2416daaffb31Sdp	shift $(($OPTIND - 1))
2417cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2418daaffb31Sdp		flist_from_teamware "$*"
2419cdf0c1d5Smjnelson	else
2420cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2421cdf0c1d5Smjnelson		exit 1
2422cdf0c1d5Smjnelson	fi
2423daaffb31Sdp	flist_done=1
2424daaffb31Sdp	shift $#
2425daaffb31Sdpelif [[ -n $wflag ]]; then
2426daaffb31Sdp	#
2427daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2428daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2429daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2430daaffb31Sdp	# in building the index.html file.
2431daaffb31Sdp	#
2432daaffb31Sdp	shift $(($OPTIND - 1))
2433daaffb31Sdp	wxfile=$1
2434daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2435daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2436daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2437daaffb31Sdp		fi
2438daaffb31Sdp	fi
2439daaffb31Sdp
2440daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2441daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2442daaffb31Sdp
2443cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2444cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2445cdf0c1d5Smjnelson		usage
2446cdf0c1d5Smjnelson	fi
2447cdf0c1d5Smjnelson
2448daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2449daaffb31Sdp	flist_from_wx $wxfile
2450daaffb31Sdp	flist_done=1
2451daaffb31Sdp	if [[ -n "$*" ]]; then
2452daaffb31Sdp		shift
2453daaffb31Sdp	fi
245414983201Sdpelif [[ $flist_mode == "stdin" ]]; then
245514983201Sdp	print -u2 " File list from: standard input"
245614983201Sdpelif [[ $flist_mode == "file" ]]; then
245714983201Sdp	print -u2 " File list from: $flist_file"
2458daaffb31Sdpfi
2459daaffb31Sdp
2460daaffb31Sdpif [[ $# -gt 0 ]]; then
246114983201Sdp	print -u2 "WARNING: unused arguments: $*"
2462daaffb31Sdpfi
2463daaffb31Sdp
24642d9224a3SMark J. Nelson#
24652d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS
24662d9224a3SMark J. Nelson# and CODEMGR_WS as needed.  Here, we set the parent workspace.
24672d9224a3SMark J. Nelson#
24682d9224a3SMark J. Nelson
2469daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
24702d9224a3SMark J. Nelson
2471daaffb31Sdp	#
24722d9224a3SMark J. Nelson	# Teamware priorities:
2473daaffb31Sdp	#
24742d9224a3SMark J. Nelson	#      1) via -p command line option
2475daaffb31Sdp	#      2) in the user environment
2476daaffb31Sdp	#      3) in the flist
24772d9224a3SMark J. Nelson	#      4) automatically based on the workspace
2478daaffb31Sdp	#
2479daaffb31Sdp
2480daaffb31Sdp	#
24812d9224a3SMark J. Nelson	# For 1, codemgr_parent will already be set.  Here's 2:
2482daaffb31Sdp	#
2483daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2484daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2485daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2486daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
24877c478bd9Sstevel@tonic-gate		exit 1
24887c478bd9Sstevel@tonic-gate	fi
24897c478bd9Sstevel@tonic-gate
2490daaffb31Sdp	#
2491daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2492daaffb31Sdp	# list, then see if we can get it by probing for wx.
2493daaffb31Sdp	#
249414983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
249514983201Sdp		if [[ ! -x $WX ]]; then
249614983201Sdp			print -u2 "WARNING: wx not found!"
2497daaffb31Sdp		fi
24987c478bd9Sstevel@tonic-gate
2499daaffb31Sdp		#
2500daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2501daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2502daaffb31Sdp		# hang asking us to initialize our wx information.
2503daaffb31Sdp		#
250414983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2505daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2506daaffb31Sdp			$WX list -w > $FLIST
2507daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2508daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2509daaffb31Sdp			print -u2 "done"
2510daaffb31Sdp			flist_done=1
2511daaffb31Sdp		fi
2512daaffb31Sdp	fi
2513daaffb31Sdp
2514daaffb31Sdp	#
2515daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2516daaffb31Sdp	# from the command line), eval it to extract environment variables from
25172d9224a3SMark J. Nelson	# it: This is method 3 for finding the parent.
2518daaffb31Sdp	#
2519daaffb31Sdp	if [[ -z $flist_done ]]; then
2520daaffb31Sdp		flist_from_teamware
2521daaffb31Sdp	fi
25222d9224a3SMark J. Nelson	env_from_flist
2523daaffb31Sdp
2524daaffb31Sdp	#
2525daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2526daaffb31Sdp	# from workspace.
2527daaffb31Sdp	#
2528daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2529daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2530daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2531daaffb31Sdp		exit 1
2532daaffb31Sdp	fi
2533daaffb31Sdp
2534daaffb31Sdp	PWS=$codemgr_parent
2535cdf0c1d5Smjnelson
2536cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2537cdf0c1d5Smjnelson
2538cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2539cdf0c1d5Smjnelson	#
2540cdf0c1d5Smjnelson	# Parent can either be specified with -p
2541cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2542cdf0c1d5Smjnelson	# or taken from hg's default path.
2543cdf0c1d5Smjnelson	#
2544cdf0c1d5Smjnelson
2545cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2546cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2547cdf0c1d5Smjnelson	fi
2548cdf0c1d5Smjnelson
2549cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2550cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2551cdf0c1d5Smjnelson	fi
2552cdf0c1d5Smjnelson
2553cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2554cdf0c1d5Smjnelson	PWS=$codemgr_parent
2555cdf0c1d5Smjnelson
2556cdf0c1d5Smjnelson	#
2557cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2558cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2559cdf0c1d5Smjnelson	#
2560cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2561cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2562cdf0c1d5Smjnelson	else
2563cdf0c1d5Smjnelson		real_parent=$PWS
2564cdf0c1d5Smjnelson	fi
2565cdf0c1d5Smjnelson
2566cdf0c1d5Smjnelson	#
2567cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2568cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2569cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2570cdf0c1d5Smjnelson	# files mentioned in the flist.
2571cdf0c1d5Smjnelson	#
2572cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2573cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2574cdf0c1d5Smjnelson		flist_done=1
2575cdf0c1d5Smjnelson	fi
2576cdf0c1d5Smjnelson
2577cdf0c1d5Smjnelson	#
2578cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2579cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2580cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2581cdf0c1d5Smjnelson	# in the user-specified flist.
2582cdf0c1d5Smjnelson	#
2583cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2584cdf0c1d5Smjnelson		env_from_flist
2585cdf0c1d5Smjnelson	fi
2586cdf0c1d5Smjnelson
2587cdf0c1d5Smjnelson	#
2588cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2589cdf0c1d5Smjnelson	#
2590cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2591cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2592cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2593cdf0c1d5Smjnelson		print " Done."
2594cdf0c1d5Smjnelson	fi
2595cdf0c1d5Smjnelson
2596cdf0c1d5Smjnelson	#
2597cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2598cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2599cdf0c1d5Smjnelson	# if we don't have one.
2600cdf0c1d5Smjnelson	#
2601cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2602b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2603cdf0c1d5Smjnelson	fi
2604cdf0c1d5Smjnelson
2605cdf0c1d5Smjnelson	#
2606cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2607cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2608cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2609cdf0c1d5Smjnelson	#
2610cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2611cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2612b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2613cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2614cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2615cdf0c1d5Smjnelson		exit 1
2616cdf0c1d5Smjnelson	fi
2617cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2618cdf0c1d5Smjnelson
2619cdf0c1d5Smjnelson	#
2620cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2621cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2622cdf0c1d5Smjnelson	#
2623cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2624cdf0c1d5Smjnelson
2625cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2626cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2627cdf0c1d5Smjnelson	fi
2628cdf0c1d5Smjnelsonelse
2629cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2630cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2631cdf0c1d5Smjnelson    else
2632cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2633cdf0c1d5Smjnelson    fi
2634cdf0c1d5Smjnelson
2635cdf0c1d5Smjnelson    env_from_flist
2636cdf0c1d5Smjnelson
2637cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2638cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2639cdf0c1d5Smjnelson	exit 1
2640cdf0c1d5Smjnelson    fi
2641cdf0c1d5Smjnelson
2642cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2643cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2644cdf0c1d5Smjnelson	exit 1
2645cdf0c1d5Smjnelson    fi
2646cdf0c1d5Smjnelson
2647cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2648cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2649daaffb31Sdpfi
2650daaffb31Sdp
2651daaffb31Sdp#
2652daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2653daaffb31Sdp# webrev-info file in the workspace directory.
2654daaffb31Sdp#
2655daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2656daaffb31Sdp	iflag=1
2657daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2658daaffb31Sdpfi
2659daaffb31Sdp
2660daaffb31Sdpif [[ -n $iflag ]]; then
2661daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2662daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2663daaffb31Sdp		    "not readable."
2664daaffb31Sdp		exit 1
2665daaffb31Sdp	else
2666daaffb31Sdp		#
2667daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2668daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2669daaffb31Sdp		#
2670daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2671daaffb31Sdp	fi
2672daaffb31Sdpfi
2673daaffb31Sdp
26740fd2682eSMark J. Nelson# DO_EVERYTHING: break point
26750fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
26760fd2682eSMark J. Nelson	break
26770fd2682eSMark J. Nelsonfi
26780fd2682eSMark J. Nelson
26790fd2682eSMark J. Nelsontypeset -A itsinfo
26800fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
26810fd2682eSMark J. Nelsonvalid_prefixes=
26820fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
26830fd2682eSMark J. Nelson	DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
26840fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
26850fd2682eSMark J. Nelson		REGFILE=$ITSREG
26860fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
26870fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
26880fd2682eSMark J. Nelson	else
26890fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
26900fd2682eSMark J. Nelson	fi
26910fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
26920fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
26930fd2682eSMark J. Nelson		exit 1
26940fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
26950fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
26960fd2682eSMark J. Nelson	fi
26970fd2682eSMark J. Nelson
26980fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
26990fd2682eSMark J. Nelson
27000fd2682eSMark J. Nelson		name=${LINE%%=*}
27010fd2682eSMark J. Nelson		value="${LINE#*=}"
27020fd2682eSMark J. Nelson
27030fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
27040fd2682eSMark J. Nelson			p=${value}
27050fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
27060fd2682eSMark J. Nelson		else
27070fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
27080fd2682eSMark J. Nelson		fi
27090fd2682eSMark J. Nelson	done
27100fd2682eSMark J. Nelson
27110fd2682eSMark J. Nelson
27120fd2682eSMark J. Nelson	DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
27130fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
27140fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
27150fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
27160fd2682eSMark J. Nelson	fi
27170fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
27180fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
27190fd2682eSMark J. Nelson	fi
27200fd2682eSMark J. Nelson	its_domain=
27210fd2682eSMark J. Nelson	its_priority=
27220fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
27230fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
27240fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
27250fd2682eSMark J. Nelson			exit 1
27260fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
27270fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
27280fd2682eSMark J. Nelson		fi
27290fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
27300fd2682eSMark J. Nelson		    eval "${LINE}"
27310fd2682eSMark J. Nelson		done
27320fd2682eSMark J. Nelson	done
27330fd2682eSMark J. Nelson
27340fd2682eSMark J. Nelson	#
27350fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
27360fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
27370fd2682eSMark J. Nelson	#
27380fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
27390fd2682eSMark J. Nelson	#
27400fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
27410fd2682eSMark J. Nelson		#
27420fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
27430fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
27440fd2682eSMark J. Nelson		#
27450fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
27460fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
27470fd2682eSMark J. Nelson		else
27480fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
27490fd2682eSMark J. Nelson		fi
27500fd2682eSMark J. Nelson
27510fd2682eSMark J. Nelson		#
27520fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
27530fd2682eSMark J. Nelson		# to this information tracking system should resolve through
27540fd2682eSMark J. Nelson		# the same URL.
27550fd2682eSMark J. Nelson		#
27560fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
27570fd2682eSMark J. Nelson		#
27580fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
27590fd2682eSMark J. Nelson		# INTERNAL_URL.
27600fd2682eSMark J. Nelson		#
27610fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
27620fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
27630fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
27640fd2682eSMark J. Nelson				break
27650fd2682eSMark J. Nelson			fi
27660fd2682eSMark J. Nelson		done
27670fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
27680fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
27690fd2682eSMark J. Nelson		fi
27700fd2682eSMark J. Nelson
27710fd2682eSMark J. Nelson		#
27720fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
27730fd2682eSMark J. Nelson		#
27740fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
27750fd2682eSMark J. Nelson
27760fd2682eSMark J. Nelson		print "/^${p}[ 	]/ {
27770fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27780fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
27790fd2682eSMark J. Nelson			}" >> ${its_sed_script}
27800fd2682eSMark J. Nelson	done
27810fd2682eSMark J. Nelson
27820fd2682eSMark J. Nelson	#
27830fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
27840fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
27850fd2682eSMark J. Nelson	#
27860fd2682eSMark J. Nelson	for p in ${its_priority}; do
27870fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
27880fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27890fd2682eSMark J. Nelson			}" >> ${its_sed_script}
27900fd2682eSMark J. Nelson	done
27910fd2682eSMark J. Nelsonfi
27920fd2682eSMark J. Nelson
27930fd2682eSMark J. Nelson#
27940fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
27950fd2682eSMark J. Nelson# and explanation of this terminator.
27960fd2682eSMark J. Nelson#
27970fd2682eSMark J. Nelsondone
27980fd2682eSMark J. Nelson
2799daaffb31Sdp#
2800daaffb31Sdp# Output directory.
2801daaffb31Sdp#
2802daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2803daaffb31Sdp
2804daaffb31Sdp#
280502d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
280602d26c39SVladimir Kotal# in the future this could potentially be an option.
2807daaffb31Sdp#
280802d26c39SVladimir Kotalif [[ -n $oflag ]]; then
280902d26c39SVladimir Kotal	WNAME=${WDIR##*/}
281002d26c39SVladimir Kotalelse
2811daaffb31Sdp	WNAME=${CWS##*/}
281202d26c39SVladimir Kotalfi
281302d26c39SVladimir Kotal
2814ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2815ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2816b0088928SVladimir Kotal	#
2817ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2818ba44d8a2SVladimir Kotal	# the default values.
2819b0088928SVladimir Kotal	#
2820ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2821ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2822ba44d8a2SVladimir Kotal	else
2823b0088928SVladimir Kotal		#
2824b0088928SVladimir Kotal		# Check upload target prefix first.
2825b0088928SVladimir Kotal		#
2826b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
2827b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
2828b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
2829b0088928SVladimir Kotal			    "($remote_target)"
2830b0088928SVladimir Kotal			exit 1
2831b0088928SVladimir Kotal		fi
2832b0088928SVladimir Kotal		#
2833ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2834ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2835ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2836ba44d8a2SVladimir Kotal		# local webrev directory name.
2837b0088928SVladimir Kotal		#
2838b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
2839b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
2840ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2841b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
2842ba44d8a2SVladimir Kotal			fi
2843b0088928SVladimir Kotal		else
2844b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
2845b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
2846b0088928SVladimir Kotal					"($remote_target)"
2847b0088928SVladimir Kotal				exit 1
2848b0088928SVladimir Kotal			else
2849b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
2850ba44d8a2SVladimir Kotal			fi
2851ba44d8a2SVladimir Kotal		fi
2852ba44d8a2SVladimir Kotal	fi
2853ba44d8a2SVladimir Kotal
2854b0088928SVladimir Kotal	#
2855b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
2856b0088928SVladimir Kotal	# specification separately.
2857b0088928SVladimir Kotal	#
2858b0088928SVladimir Kotal	remote_target=${remote_target%/}
2859b0088928SVladimir Kotalfi
2860b0088928SVladimir Kotal
2861b0088928SVladimir Kotal#
2862ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2863b0088928SVladimir Kotal#
2864ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2865b0088928SVladimir Kotal	delete_webrev 1 1
2866ba44d8a2SVladimir Kotal	exit $?
2867ba44d8a2SVladimir Kotalfi
2868ba44d8a2SVladimir Kotal
2869b0088928SVladimir Kotal#
2870ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2871b0088928SVladimir Kotal#
2872ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2873ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2874b0088928SVladimir Kotal		delete_webrev 1 1
2875ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2876ba44d8a2SVladimir Kotal	fi
2877ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
287802d26c39SVladimir Kotal		upload_webrev
287902d26c39SVladimir Kotal		exit $?
288002d26c39SVladimir Kotal	fi
2881ba44d8a2SVladimir Kotalfi
2882daaffb31Sdp
2883e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
28847c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
28857c478bd9Sstevel@tonic-gatefi
2886daaffb31Sdp
2887daaffb31Sdpif [[ ! -d $WDIR ]]; then
2888daaffb31Sdp	mkdir -p $WDIR
2889ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
28907c478bd9Sstevel@tonic-gatefi
28917c478bd9Sstevel@tonic-gate
2892daaffb31Sdp#
2893daaffb31Sdp# Summarize what we're going to do.
2894daaffb31Sdp#
2895cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2896cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2897cdf0c1d5Smjnelsonelse
2898daaffb31Sdp	print "      Workspace: $CWS"
2899cdf0c1d5Smjnelsonfi
2900daaffb31Sdpif [[ -n $parent_webrev ]]; then
2901daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2902daaffb31Sdpelse
2903cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2904cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2905b0088928SVladimir Kotal			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2906cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2907cdf0c1d5Smjnelson	else
2908daaffb31Sdp		print "Compare against: $PWS"
2909daaffb31Sdp	fi
2910cdf0c1d5Smjnelsonfi
2911daaffb31Sdp
2912daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2913daaffb31Sdpprint "      Output to: $WDIR"
2914daaffb31Sdp
2915daaffb31Sdp#
29167c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2917daaffb31Sdp#
2918daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
29197c478bd9Sstevel@tonic-gate
2920daaffb31Sdprm -f $WDIR/$WNAME.patch
2921daaffb31Sdprm -f $WDIR/$WNAME.ps
2922daaffb31Sdprm -f $WDIR/$WNAME.pdf
29237c478bd9Sstevel@tonic-gate
2924daaffb31Sdptouch $WDIR/$WNAME.patch
29257c478bd9Sstevel@tonic-gate
2926daaffb31Sdpprint "   Output Files:"
2927daaffb31Sdp
2928daaffb31Sdp#
2929daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2930daaffb31Sdp#
2931b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2932daaffb31SdpFLIST=/tmp/$$.flist.clean
2933daaffb31Sdp
2934daaffb31Sdp#
2935cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2936cdf0c1d5Smjnelson#
2937cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2938cdf0c1d5Smjnelson	#
2939cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2940cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2941cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2942cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2943cdf0c1d5Smjnelson	#    keep only the old name.
2944cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2945cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2946cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2947cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2948cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2949e6ccc173SEdward Pilatowicz	# 4) Eliminate any duplicate entries.  (This can occur if a
2950e6ccc173SEdward Pilatowicz	#    file has been used as the source of an hg cp and it's
2951e6ccc173SEdward Pilatowicz	#    also been modified in the same changeset.)
2952cdf0c1d5Smjnelson	#
2953cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2954b0088928SVladimir Kotal	$SED '
2955cdf0c1d5Smjnelson		s#^[^ ]* ##
2956cdf0c1d5Smjnelson		s#/#\\\/#g
2957cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2958e6ccc173SEdward Pilatowicz	' < $FLIST | $SORT -u > $SEDFILE
2959cdf0c1d5Smjnelson
2960cdf0c1d5Smjnelson	#
2961cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2962cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2963cdf0c1d5Smjnelson	#
2964cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2965cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2966b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2967cdf0c1d5Smjnelsonfi
2968cdf0c1d5Smjnelson
2969cdf0c1d5Smjnelson#
2970daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2971daaffb31Sdp#
2972daaffb31Sdpcat $FLIST | while read LINE
29737c478bd9Sstevel@tonic-gatedo
29747c478bd9Sstevel@tonic-gate	set - $LINE
29757c478bd9Sstevel@tonic-gate	P=$1
29767c478bd9Sstevel@tonic-gate
2977daaffb31Sdp	#
2978daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2979daaffb31Sdp	# file that has been modified or created in the child.  A file
2980daaffb31Sdp	# that is renamed in the child workspace has two names on the
2981daaffb31Sdp	# line: new name followed by the old name.
2982daaffb31Sdp	#
2983daaffb31Sdp	oldname=""
2984daaffb31Sdp	oldpath=""
2985daaffb31Sdp	rename=
2986daaffb31Sdp	if [[ $# -eq 2 ]]; then
29877c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2988e6ccc173SEdward Pilatowicz		if [[ -f $PP ]]; then
2989e6ccc173SEdward Pilatowicz			oldname=" (copied from $PP)"
2990e6ccc173SEdward Pilatowicz		else
2991e6ccc173SEdward Pilatowicz			oldname=" (renamed from $PP)"
2992e6ccc173SEdward Pilatowicz		fi
2993daaffb31Sdp		oldpath="$PP"
2994daaffb31Sdp		rename=1
29957c478bd9Sstevel@tonic-gate		PDIR=${PP%/*}
2996daaffb31Sdp		if [[ $PDIR == $PP ]]; then
29977c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
29987c478bd9Sstevel@tonic-gate		fi
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate		PF=${PP##*/}
30017c478bd9Sstevel@tonic-gate
30027c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3003daaffb31Sdp		if [[ $DIR == $P ]]; then
30047c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
30057c478bd9Sstevel@tonic-gate		fi
30067c478bd9Sstevel@tonic-gate
30077c478bd9Sstevel@tonic-gate		F=${P##*/}
3008daaffb31Sdp
30097c478bd9Sstevel@tonic-gate        else
30107c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3011daaffb31Sdp		if [[ "$DIR" == "$P" ]]; then
30127c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
30137c478bd9Sstevel@tonic-gate		fi
30147c478bd9Sstevel@tonic-gate
30157c478bd9Sstevel@tonic-gate		F=${P##*/}
30167c478bd9Sstevel@tonic-gate
30177c478bd9Sstevel@tonic-gate		PP=$P
30187c478bd9Sstevel@tonic-gate		PDIR=$DIR
30197c478bd9Sstevel@tonic-gate		PF=$F
30207c478bd9Sstevel@tonic-gate	fi
30217c478bd9Sstevel@tonic-gate
3022daaffb31Sdp	COMM=`getcomments html $P $PP`
30237c478bd9Sstevel@tonic-gate
3024daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
30257c478bd9Sstevel@tonic-gate
30267c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
30277c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
30287c478bd9Sstevel@tonic-gate
3029daaffb31Sdp	#
3030cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
3031daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
3032daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
3033daaffb31Sdp	#
3034daaffb31Sdp
3035cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
30367c478bd9Sstevel@tonic-gate	    continue
30377c478bd9Sstevel@tonic-gate
3038cdf0c1d5Smjnelson	#
3039cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3040cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3041cdf0c1d5Smjnelson	# consistent environment.
3042cdf0c1d5Smjnelson	#
3043cdf0c1d5Smjnelson	OWD=$PWD
3044daaffb31Sdp	cd $WDIR/raw_files
3045daaffb31Sdp	ofile=old/$PDIR/$PF
3046daaffb31Sdp	nfile=new/$DIR/$F
30477c478bd9Sstevel@tonic-gate
3048daaffb31Sdp	mv_but_nodiff=
3049daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3050daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3051daaffb31Sdp		mv_but_nodiff=1
3052daaffb31Sdp	fi
3053daaffb31Sdp
3054daaffb31Sdp	#
3055daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3056daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3057daaffb31Sdp	#
3058daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3059daaffb31Sdp	#	  diff and an 'add' diff
3060daaffb31Sdp	#	- new files and deleted files must be handled specially
3061daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
3062daaffb31Sdp	#	  (and hence renames) as of this writing.
3063daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
3064daaffb31Sdp	#	  output of Solaris diff properly when it comes to
3065daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
3066daaffb31Sdp	#         transformations:
3067daaffb31Sdp	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3068daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3069daaffb31Sdp	#
3070b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3071b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3072daaffb31Sdp
3073daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3074daaffb31Sdp	if [[ -z $rename ]]; then
3075e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3076daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3077daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3078e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3079daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3080daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3081daaffb31Sdp		else
3082daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3083daaffb31Sdp		fi
3084daaffb31Sdp	else
3085daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3086daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3087daaffb31Sdp
3088daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3089daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3090daaffb31Sdp	fi
3091daaffb31Sdp
3092daaffb31Sdp	#
3093daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3094daaffb31Sdp	# whole wad.
3095daaffb31Sdp	#
3096daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3097daaffb31Sdp
3098daaffb31Sdp	print " patch\c"
3099daaffb31Sdp
3100daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3101daaffb31Sdp
3102daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3103daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3104daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
31057c478bd9Sstevel@tonic-gate		print " cdiffs\c"
31067c478bd9Sstevel@tonic-gate
3107daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3108daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3109daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
3110daaffb31Sdp
31117c478bd9Sstevel@tonic-gate		print " udiffs\c"
31127c478bd9Sstevel@tonic-gate
31137c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3114daaffb31Sdp			$WDIFF -c "$COMM" \
3115daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3116daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3117daaffb31Sdp			if [[ $? -eq 0 ]]; then
31187c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3119daaffb31Sdp			else
3120daaffb31Sdp				print " wdiffs[fail]\c"
3121daaffb31Sdp			fi
31227c478bd9Sstevel@tonic-gate		fi
31237c478bd9Sstevel@tonic-gate
3124daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3125daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
31267c478bd9Sstevel@tonic-gate		print " sdiffs\c"
31277c478bd9Sstevel@tonic-gate
31287c478bd9Sstevel@tonic-gate		print " frames\c"
31297c478bd9Sstevel@tonic-gate
31307c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
31317c478bd9Sstevel@tonic-gate
3132daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3133daaffb31Sdp
3134daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3135daaffb31Sdp		# renamed file: may also have differences
3136daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3137daaffb31Sdp	elif [[ -f $nfile ]]; then
31387c478bd9Sstevel@tonic-gate		# new file: count added lines
3139daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3140daaffb31Sdp	elif [[ -f $ofile ]]; then
31417c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3142daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
31437c478bd9Sstevel@tonic-gate	fi
31447c478bd9Sstevel@tonic-gate
3145daaffb31Sdp	#
3146daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3147daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3148daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3149daaffb31Sdp	#
3150daaffb31Sdp	if [[ -f $nfile ]]; then
3151daaffb31Sdp		ocr=$ofile
3152daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3153daaffb31Sdp
3154daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3155daaffb31Sdp			textcomm=`getcomments text $P $PP`
315614983201Sdp			if [[ -x $CODEREVIEW ]]; then
315714983201Sdp				$CODEREVIEW -y "$textcomm" \
315814983201Sdp				    -e $ocr $nfile \
315914983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
316014983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3161daaffb31Sdp				if [[ $? -eq 0 ]]; then
3162daaffb31Sdp					print " ps\c"
3163daaffb31Sdp				else
3164daaffb31Sdp					print " ps[fail]\c"
3165daaffb31Sdp				fi
3166daaffb31Sdp			fi
3167daaffb31Sdp		fi
316814983201Sdp	fi
3169daaffb31Sdp
3170cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3171cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
31727c478bd9Sstevel@tonic-gate		print " old\c"
31737c478bd9Sstevel@tonic-gate	fi
31747c478bd9Sstevel@tonic-gate
3175daaffb31Sdp	if [[ -f $nfile ]]; then
3176daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
31777c478bd9Sstevel@tonic-gate		print " new\c"
31787c478bd9Sstevel@tonic-gate	fi
31797c478bd9Sstevel@tonic-gate
3180cdf0c1d5Smjnelson	cd $OWD
3181cdf0c1d5Smjnelson
3182daaffb31Sdp	print
31837c478bd9Sstevel@tonic-gatedone
31847c478bd9Sstevel@tonic-gate
3185daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
31867c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3187daaffb31Sdp
318814983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
318914983201Sdp	print " Generating PDF: Skipped: no output available"
319014983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
319114983201Sdp	print " Generating PDF: \c"
319214983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3193daaffb31Sdp	print "Done."
319414983201Sdpelse
319514983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
319614983201Sdpfi
31977c478bd9Sstevel@tonic-gate
3198e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3199e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3200e0e0293aSjmcp
3201e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3202ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3203e0e0293aSjmcpfi
3204e0e0293aSjmcp
32057c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
32067c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
32077c478bd9Sstevel@tonic-gate
32087c478bd9Sstevel@tonic-gatecd $CWS
32097c478bd9Sstevel@tonic-gate
32107c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3211daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
32127c478bd9Sstevel@tonic-gate
3213daaffb31Sdpprint "     index.html: \c"
32147c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
32157c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
32167c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
32177c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
32187c478bd9Sstevel@tonic-gate
3219daaffb31Sdpprint "$HTML<head>$STDHEAD"
3220daaffb31Sdpprint "<title>$WNAME</title>"
3221daaffb31Sdpprint "</head>"
3222daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3223daaffb31Sdpprint "<div class=\"summary\">"
3224daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
32257c478bd9Sstevel@tonic-gate
3226daaffb31Sdpprint "<table>"
32277c478bd9Sstevel@tonic-gate
3228daaffb31Sdp#
3229cdf0c1d5Smjnelson# Get the preparer's name:
3230daaffb31Sdp#
3231cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3232cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3233cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3234cdf0c1d5Smjnelson#
3235cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3236cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3237cdf0c1d5Smjnelson#
3238cdf0c1d5Smjnelsonpreparer=
3239cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3240cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3241cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3242cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3243cdf0c1d5Smjnelson	fi
3244cdf0c1d5Smjnelsonfi
3245cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3246cdf0c1d5Smjnelson	preparer=$(
3247cdf0c1d5Smjnelson	    $PERL -e '
3248cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3249cdf0c1d5Smjnelson	        if ($login) {
3250cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3251cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3252cdf0c1d5Smjnelson	        } else {
3253cdf0c1d5Smjnelson	            printf "(unknown)\n";
3254cdf0c1d5Smjnelson	        }
3255cdf0c1d5Smjnelson	')
3256daaffb31Sdpfi
3257daaffb31Sdp
325848bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
325948bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
3260cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
3261cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
3262cdf0c1d5Smjnelson	print "(at $CWS_REV)"
3263cdf0c1d5Smjnelsonfi
3264cdf0c1d5Smjnelsonprint "</td></tr>"
3265daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3266daaffb31Sdpif [[ -n $parent_webrev ]]; then
3267daaffb31Sdp	print "webrev at $parent_webrev"
3268daaffb31Sdpelse
3269daaffb31Sdp	print "$PWS"
3270cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
3271cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
3272cdf0c1d5Smjnelson	fi
3273daaffb31Sdpfi
3274daaffb31Sdpprint "</td></tr>"
3275daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3276daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3277daaffb31Sdpprint "</td></tr>"
3278daaffb31Sdp
3279daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3280371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3281daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3282371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3283daaffb31Sdpfi
3284daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3285371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3286daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3287371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3288daaffb31Sdpfi
3289daaffb31Sdp
3290daaffb31Sdpif [[ -n "$iflag" ]]; then
3291daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3292daaffb31Sdp	cat /tmp/$$.include
3293daaffb31Sdp	print "</div></td></tr>"
3294daaffb31Sdpfi
3295daaffb31Sdpprint "</table>"
3296daaffb31Sdpprint "</div>"
3297daaffb31Sdp
3298daaffb31Sdp#
3299daaffb31Sdp# Second pass through the files: generate the rest of the index file
3300daaffb31Sdp#
3301daaffb31Sdpcat $FLIST | while read LINE
33027c478bd9Sstevel@tonic-gatedo
33037c478bd9Sstevel@tonic-gate	set - $LINE
33047c478bd9Sstevel@tonic-gate	P=$1
33057c478bd9Sstevel@tonic-gate
3306daaffb31Sdp	if [[ $# == 2 ]]; then
33077c478bd9Sstevel@tonic-gate		PP=$2
3308cdf0c1d5Smjnelson		oldname="$PP"
33097c478bd9Sstevel@tonic-gate	else
33107c478bd9Sstevel@tonic-gate		PP=$P
3311daaffb31Sdp		oldname=""
3312daaffb31Sdp	fi
3313daaffb31Sdp
3314cdf0c1d5Smjnelson	mv_but_nodiff=
3315cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3316cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3317cdf0c1d5Smjnelson		mv_but_nodiff=1
3318cdf0c1d5Smjnelson	fi
3319cdf0c1d5Smjnelson
3320daaffb31Sdp	DIR=${P%/*}
3321daaffb31Sdp	if [[ $DIR == $P ]]; then
3322daaffb31Sdp		DIR="."   # File at root of workspace
33237c478bd9Sstevel@tonic-gate	fi
33247c478bd9Sstevel@tonic-gate
33257c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
33267c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
33277c478bd9Sstevel@tonic-gate	# appear twice in the file list
33287c478bd9Sstevel@tonic-gate
33297c478bd9Sstevel@tonic-gate	F=$WDIR/$P
33307c478bd9Sstevel@tonic-gate
3331daaffb31Sdp	print "<p>"
33327c478bd9Sstevel@tonic-gate
33337c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
33347c478bd9Sstevel@tonic-gate
3335daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3336371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3337371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3338371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3339371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
33407c478bd9Sstevel@tonic-gate
3341daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3342371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3343371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
33447c478bd9Sstevel@tonic-gate		fi
33457c478bd9Sstevel@tonic-gate
3346371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3347371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
33487c478bd9Sstevel@tonic-gate
3349371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3350371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
33517c478bd9Sstevel@tonic-gate	else
3352daaffb31Sdp		print " ------ ------ ------"
33537c478bd9Sstevel@tonic-gate
3354daaffb31Sdp		if [[ -x $WDIFF ]]; then
33557c478bd9Sstevel@tonic-gate			print " ------"
33567c478bd9Sstevel@tonic-gate		fi
3357daaffb31Sdp
3358daaffb31Sdp		print " ------"
33597c478bd9Sstevel@tonic-gate	fi
33607c478bd9Sstevel@tonic-gate
33617c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
33627c478bd9Sstevel@tonic-gate
3363daaffb31Sdp	if [[ -f $F-.html ]]; then
3364371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3365371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
33667c478bd9Sstevel@tonic-gate	else
3367daaffb31Sdp		print " ---"
33687c478bd9Sstevel@tonic-gate	fi
33697c478bd9Sstevel@tonic-gate
33707c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
33717c478bd9Sstevel@tonic-gate
3372daaffb31Sdp	if [[ -f $F.html ]]; then
3373371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3374371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
33757c478bd9Sstevel@tonic-gate	else
3376daaffb31Sdp		print " ---"
33777c478bd9Sstevel@tonic-gate	fi
33787c478bd9Sstevel@tonic-gate
3379daaffb31Sdp	if [[ -f $F.patch ]]; then
3380371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3381371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3382daaffb31Sdp	else
3383daaffb31Sdp		print " -----"
3384daaffb31Sdp	fi
3385daaffb31Sdp
3386daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3387371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3388371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3389daaffb31Sdp	else
3390daaffb31Sdp		print " ---"
3391daaffb31Sdp	fi
3392daaffb31Sdp
3393cdf0c1d5Smjnelson	print "<b>$P</b>"
3394cdf0c1d5Smjnelson
3395cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3396e6ccc173SEdward Pilatowicz	if [[ -f "$oldname" ]]; then
3397cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3398e6ccc173SEdward Pilatowicz			print "<i>(copied from $oldname)</i>"
3399cdf0c1d5Smjnelson		else
3400e6ccc173SEdward Pilatowicz			print "<i>(copied and modified from $oldname)</i>"
3401e6ccc173SEdward Pilatowicz		fi
3402e6ccc173SEdward Pilatowicz	elif [[ -n "$oldname" ]]; then
3403e6ccc173SEdward Pilatowicz		if [[ -n "$mv_but_nodiff" ]]; then
3404e6ccc173SEdward Pilatowicz			print "<i>(renamed from $oldname)</i>"
3405e6ccc173SEdward Pilatowicz		else
3406e6ccc173SEdward Pilatowicz			print "<i>(renamed and modified from $oldname)</i>"
3407cdf0c1d5Smjnelson		fi
3408cdf0c1d5Smjnelson	fi
3409cdf0c1d5Smjnelson
3410cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3411cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3412cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3413cdf0c1d5Smjnelson	fi
3414daaffb31Sdp
3415daaffb31Sdp	#
3416e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3417daaffb31Sdp	#
3418daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3419e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3420e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3421daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3422daaffb31Sdp			    "this review</i>"
3423daaffb31Sdp		fi
3424daaffb31Sdp	fi
3425daaffb31Sdp
3426daaffb31Sdp	print "</p>"
34277c478bd9Sstevel@tonic-gate	# Insert delta comments
34287c478bd9Sstevel@tonic-gate
3429daaffb31Sdp	print "<blockquote><pre>"
3430daaffb31Sdp	getcomments html $P $PP
3431daaffb31Sdp	print "</pre>"
34327c478bd9Sstevel@tonic-gate
34337c478bd9Sstevel@tonic-gate	# Add additional comments comment
34347c478bd9Sstevel@tonic-gate
3435daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
34367c478bd9Sstevel@tonic-gate
34377c478bd9Sstevel@tonic-gate	# Add count of changes.
34387c478bd9Sstevel@tonic-gate
3439daaffb31Sdp	if [[ -f $F.count ]]; then
34407c478bd9Sstevel@tonic-gate	    cat $F.count
34417c478bd9Sstevel@tonic-gate	    rm $F.count
34427c478bd9Sstevel@tonic-gate	fi
3443cdf0c1d5Smjnelson
3444cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3445cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3446cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3447cdf0c1d5Smjnelson
3448cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3449cdf0c1d5Smjnelson		# 1) New executable files
3450cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3451cdf0c1d5Smjnelson		# 3) Existing executable files
3452cdf0c1d5Smjnelson
3453cdf0c1d5Smjnelson		old_mode=
3454cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3455cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3456cdf0c1d5Smjnelson		fi
3457cdf0c1d5Smjnelson
3458cdf0c1d5Smjnelson		new_mode=
3459cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3460cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3461cdf0c1d5Smjnelson		fi
3462cdf0c1d5Smjnelson
3463cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3464cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3465cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3466cdf0c1d5Smjnelson			print "</span>"
3467cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3468cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3469cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3470cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3471cdf0c1d5Smjnelson			print "</span>"
3472cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3473cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3474cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3475cdf0c1d5Smjnelson			print "</span>"
3476cdf0c1d5Smjnelson		fi
3477cdf0c1d5Smjnelson	fi
3478cdf0c1d5Smjnelson
3479daaffb31Sdp	print "</blockquote>"
34807c478bd9Sstevel@tonic-gatedone
34817c478bd9Sstevel@tonic-gate
3482daaffb31Sdpprint
3483daaffb31Sdpprint
3484cac38512Smjnelsonprint "<hr></hr>"
3485daaffb31Sdpprint "<p style=\"font-size: small\">"
34869a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3487daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3488daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3489e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3490daaffb31Sdpprint "</body>"
3491daaffb31Sdpprint "</html>"
34927c478bd9Sstevel@tonic-gate
34937c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
34947c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
34957c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
34967c478bd9Sstevel@tonic-gate
3497daaffb31Sdpprint "Done."
349802d26c39SVladimir Kotal
3499b0088928SVladimir Kotal#
3500ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3501b0088928SVladimir Kotal#
3502ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3503b0088928SVladimir Kotal	delete_webrev 1 1
3504ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3505ba44d8a2SVladimir Kotalfi
3506ba44d8a2SVladimir Kotal
350702d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
350802d26c39SVladimir Kotal	upload_webrev
350902d26c39SVladimir Kotal	exit $?
351002d26c39SVladimir Kotalfi
3511