xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 48ad9d01ac0e269db0aa65d5cb3c5e9a6d90b0f9)
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#
2478add226Sjmcp# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bd9Sstevel@tonic-gate#
26cdf0c1d5Smjnelson
272f54b716SRichard Lowe# Copyright 2008, 2010, Richard Lowe
287646c8f3SMarcel Telka# Copyright 2012 Marcel Telka <marcel@telka.sk>
29d7b56f41SBart Coddens# Copyright 2014 Bart Coddens <bart.coddens@gmail.com>
302f54b716SRichard Lowe
31cdf0c1d5Smjnelson#
32daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
33daaffb31Sdp# suitable for doing a code review of source changes via a web page.
34daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
35daaffb31Sdp# type 'webrev -h'.
367c478bd9Sstevel@tonic-gate#
37daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
38daaffb31Sdp# man page.
397c478bd9Sstevel@tonic-gate#
40daaffb31Sdp
417c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
427c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
437c478bd9Sstevel@tonic-gateNEW_COLOR=blue
447c478bd9Sstevel@tonic-gate
45daaffb31SdpHTML='<?xml version="1.0"?>
46daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
47daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
48daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
49daaffb31Sdp
50daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
51daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
52daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
53daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
54daaffb31Sdp
55cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
56*48ad9d01SRobert Mustacchi<meta http-equiv="Content-Type" content="text/xhtml;charset=utf-8"></meta>
57cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
58cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
59daaffb31Sdp<!--
60daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
61daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
62daaffb31Sdp   mechanism available in some browsers.
63daaffb31Sdp
64daaffb31Sdp   For example, to have all "removed" information be red instead of
65daaffb31Sdp   brown, set a rule in your userContent.css file like:
66daaffb31Sdp
67daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
68daaffb31Sdp-->
69daaffb31Sdp<style type="text/css" media="screen">
70daaffb31Sdpbody {
71daaffb31Sdp    background-color: #eeeeee;
72daaffb31Sdp}
73daaffb31Sdphr {
74daaffb31Sdp    border: none 0;
75daaffb31Sdp    border-top: 1px solid #aaa;
76daaffb31Sdp    height: 1px;
77daaffb31Sdp}
78daaffb31Sdpdiv.summary {
79daaffb31Sdp    font-size: .8em;
80daaffb31Sdp    border-bottom: 1px solid #aaa;
81daaffb31Sdp    padding-left: 1em;
82daaffb31Sdp    padding-right: 1em;
83daaffb31Sdp}
84daaffb31Sdpdiv.summary h2 {
85daaffb31Sdp    margin-bottom: 0.3em;
86daaffb31Sdp}
87daaffb31Sdpdiv.summary table th {
88daaffb31Sdp    text-align: right;
89daaffb31Sdp    vertical-align: top;
90daaffb31Sdp    white-space: nowrap;
91daaffb31Sdp}
92daaffb31Sdpspan.lineschanged {
93daaffb31Sdp    font-size: 0.7em;
94daaffb31Sdp}
95daaffb31Sdpspan.oldmarker {
96daaffb31Sdp    color: red;
97daaffb31Sdp    font-size: large;
98daaffb31Sdp    font-weight: bold;
99daaffb31Sdp}
100daaffb31Sdpspan.newmarker {
101daaffb31Sdp    color: green;
102daaffb31Sdp    font-size: large;
103daaffb31Sdp    font-weight: bold;
104daaffb31Sdp}
105daaffb31Sdpspan.removed {
106daaffb31Sdp    color: brown;
107daaffb31Sdp}
108daaffb31Sdpspan.changed {
109daaffb31Sdp    color: blue;
110daaffb31Sdp}
111daaffb31Sdpspan.new {
112daaffb31Sdp    color: blue;
113daaffb31Sdp    font-weight: bold;
114daaffb31Sdp}
115cdf0c1d5Smjnelsonspan.chmod {
116cdf0c1d5Smjnelson    font-size: 0.7em;
117cdf0c1d5Smjnelson    color: #db7800;
118cdf0c1d5Smjnelson}
119daaffb31Sdpa.print { font-size: x-small; }
120daaffb31Sdpa:hover { background-color: #ffcc99; }
121daaffb31Sdp</style>
122daaffb31Sdp
123daaffb31Sdp<style type="text/css" media="print">
124daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
125daaffb31Sdpspan.removed { color: #444; font-style: italic }
126daaffb31Sdpspan.changed { font-weight: bold; }
127daaffb31Sdpspan.new { font-weight: bold; }
128daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
129daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
130daaffb31Sdpa.print {display: none}
131daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
132daaffb31Sdp</style>
133daaffb31Sdp'
134daaffb31Sdp
135daaffb31Sdp#
136daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
137daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
138daaffb31Sdp#
139daaffb31SdpUDIFFCSS='
140daaffb31Sdp<style type="text/css" media="screen">
141daaffb31Sdpspan.new {
142daaffb31Sdp    color: blue;
143daaffb31Sdp    font-weight: normal;
144daaffb31Sdp}
145daaffb31Sdp</style>
146daaffb31Sdp'
147daaffb31Sdp
148b0088928SVladimir Kotal#
149b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
150b0088928SVladimir Kotal#
151b0088928SVladimir Kotalfunction print_upload_header
152b0088928SVladimir Kotal{
153b0088928SVladimir Kotal	typeset -r prefix=$1
154b0088928SVladimir Kotal	typeset display_target
155b0088928SVladimir Kotal
156b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
157b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
158b0088928SVladimir Kotal	else
159b0088928SVladimir Kotal		display_target=${remote_target}
160b0088928SVladimir Kotal	fi
161b0088928SVladimir Kotal
162b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
163b0088928SVladimir Kotal		display_target=${display_target}/
164b0088928SVladimir Kotal	fi
165b0088928SVladimir Kotal
166b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
167b0088928SVladimir Kotal	    "     Uploading: \c"
168b0088928SVladimir Kotal}
169b0088928SVladimir Kotal
170b0088928SVladimir Kotal#
17102d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
172b0088928SVladimir Kotal#
173ba44d8a2SVladimir Kotalfunction rsync_upload
17402d26c39SVladimir Kotal{
175b0088928SVladimir Kotal	if (( $# != 2 )); then
176b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
177b0088928SVladimir Kotal		exit 1
17802d26c39SVladimir Kotal	fi
17902d26c39SVladimir Kotal
180b0088928SVladimir Kotal	typeset -r dst=$1
181b0088928SVladimir Kotal	integer -r print_err_msg=$2
18202d26c39SVladimir Kotal
183b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
184b0088928SVladimir Kotal	print "rsync ... \c"
1858a34f8dcSVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
186b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
187b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
188b0088928SVladimir Kotal		return 1
189b0088928SVladimir Kotal	fi
190b0088928SVladimir Kotal	#
191b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
192b0088928SVladimir Kotal	# directory contents, not the whole directory.
193b0088928SVladimir Kotal	#
194b0088928SVladimir Kotal	typeset src_dir=$WDIR
195b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
196b0088928SVladimir Kotal		src_dir=${src_dir}/
197b0088928SVladimir Kotal	fi
198b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
19902d26c39SVladimir Kotal	if (( $? != 0 )); then
200b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
201b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
202b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
203b0088928SVladimir Kotal			print "error messages:"
204b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
205b0088928SVladimir Kotal			rm -f $err_msg
206b0088928SVladimir Kotal		fi
20702d26c39SVladimir Kotal		return 1
20802d26c39SVladimir Kotal	fi
20902d26c39SVladimir Kotal
210b0088928SVladimir Kotal	rm -f $err_msg
21102d26c39SVladimir Kotal	print "Done."
21202d26c39SVladimir Kotal	return 0
21302d26c39SVladimir Kotal}
21402d26c39SVladimir Kotal
215b0088928SVladimir Kotal#
216b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
217b0088928SVladimir Kotal# 1 on failure.
218b0088928SVladimir Kotal#
219b0088928SVladimir Kotalfunction remote_mkdirs
220b0088928SVladimir Kotal{
221b0088928SVladimir Kotal	typeset -r dir_spec=$1
2229d3952abSVladimir Kotal	typeset -r host_spec=$2
223b0088928SVladimir Kotal
224b0088928SVladimir Kotal	#
225b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
226b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
227b0088928SVladimir Kotal	# except the last one which will be created by scp.
228b0088928SVladimir Kotal	#
229b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
230b0088928SVladimir Kotal		print "mkdirs \c"
231b0088928SVladimir Kotal		#
232b0088928SVladimir Kotal		# Remove the last directory from directory specification.
233b0088928SVladimir Kotal		#
234b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
2358a34f8dcSVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP \
2368a34f8dcSVladimir Kotal		    /tmp/webrev_mkdir.XXXXXX )
237b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
238b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
239b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
240b0088928SVladimir Kotal			return 1
241b0088928SVladimir Kotal		fi
242b0088928SVladimir Kotal                OLDIFS=$IFS
243b0088928SVladimir Kotal                IFS=/
244b0088928SVladimir Kotal		typeset dir
245b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
246b0088928SVladimir Kotal			#
247b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
248b0088928SVladimir Kotal			# to avoid an error in case the directory already
249b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
250b0088928SVladimir Kotal			# there is one.
251b0088928SVladimir Kotal			#
252b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
253b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
254b0088928SVladimir Kotal                done
255b0088928SVladimir Kotal                IFS=$OLDIFS
2568a34f8dcSVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
257b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
258b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
259b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
260b0088928SVladimir Kotal			return 1
261b0088928SVladimir Kotal		fi
262b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
263b0088928SVladimir Kotal		if (( $? != 0 )); then
264b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
265b0088928SVladimir Kotal			print "error messages:"
266b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
267b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
268b0088928SVladimir Kotal			return 1
269b0088928SVladimir Kotal		fi
270b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
271b0088928SVladimir Kotal	fi
272b0088928SVladimir Kotal
273b0088928SVladimir Kotal	return 0
274b0088928SVladimir Kotal}
275b0088928SVladimir Kotal
276b0088928SVladimir Kotal#
27702d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
278b0088928SVladimir Kotal#
279ba44d8a2SVladimir Kotalfunction ssh_upload
28002d26c39SVladimir Kotal{
28102d26c39SVladimir Kotal	if (( $# != 1 )); then
282b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
283b0088928SVladimir Kotal		exit 1
28402d26c39SVladimir Kotal	fi
28502d26c39SVladimir Kotal
28602d26c39SVladimir Kotal	typeset dst=$1
28702d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
288ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
28902d26c39SVladimir Kotal
290b0088928SVladimir Kotal	#
291b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
292b0088928SVladimir Kotal	# because it will also print its progress.
293b0088928SVladimir Kotal	#
294b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
295b0088928SVladimir Kotal
296b0088928SVladimir Kotal	#
297b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
298b0088928SVladimir Kotal	# to perform it again.
299b0088928SVladimir Kotal	#
300ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
301b0088928SVladimir Kotal		#
302b0088928SVladimir Kotal		# We do not care about return value because this might be
303b0088928SVladimir Kotal		# the first time this directory is uploaded.
304b0088928SVladimir Kotal		#
305ba44d8a2SVladimir Kotal		delete_webrev 0
30602d26c39SVladimir Kotal	fi
30702d26c39SVladimir Kotal
308b0088928SVladimir Kotal	#
309b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
310b0088928SVladimir Kotal	# in remote_mkdirs function.
311b0088928SVladimir Kotal	#
3129d3952abSVladimir Kotal	remote_mkdirs ${dir_spec} ${host_spec}
31302d26c39SVladimir Kotal	if (( $? != 0 )); then
31402d26c39SVladimir Kotal		return 1
31502d26c39SVladimir Kotal	fi
31602d26c39SVladimir Kotal
317b0088928SVladimir Kotal	print "upload ... \c"
3188a34f8dcSVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
319b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
320b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
321b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
322b0088928SVladimir Kotal		return 1
323b0088928SVladimir Kotal	fi
32402d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
325b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
32602d26c39SVladimir Kotal	if (( $? != 0 )); then
327b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
328b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
329b0088928SVladimir Kotal		print "error messages:"
330b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
331b0088928SVladimir Kotal		rm -f ${scp_err_msg}
33202d26c39SVladimir Kotal		return 1
33302d26c39SVladimir Kotal	fi
33402d26c39SVladimir Kotal
335b0088928SVladimir Kotal	rm -f ${scp_err_msg}
33602d26c39SVladimir Kotal	print "Done."
33702d26c39SVladimir Kotal	return 0
33802d26c39SVladimir Kotal}
33902d26c39SVladimir Kotal
34002d26c39SVladimir Kotal#
341ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
342b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
343b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
344b0088928SVladimir Kotal# only performs deletion.
345ba44d8a2SVladimir Kotal#
346ba44d8a2SVladimir Kotalfunction delete_webrev
347ba44d8a2SVladimir Kotal{
348b0088928SVladimir Kotal	if (( $# < 1 )); then
349b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
350b0088928SVladimir Kotal		exit 1
351ba44d8a2SVladimir Kotal	fi
352ba44d8a2SVladimir Kotal
353b0088928SVladimir Kotal	integer -r check=$1
354b0088928SVladimir Kotal	integer delete_only=0
355b0088928SVladimir Kotal	if (( $# == 2 )); then
356b0088928SVladimir Kotal		delete_only=1
357b0088928SVladimir Kotal	fi
358b0088928SVladimir Kotal
359b0088928SVladimir Kotal	#
360ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
361b0088928SVladimir Kotal	#
362ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
363ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
364ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
365ba44d8a2SVladimir Kotal	typeset dir_rm
366ba44d8a2SVladimir Kotal
367b0088928SVladimir Kotal	#
368ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
369b0088928SVladimir Kotal	#
370ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
371ba44d8a2SVladimir Kotal		return 1
372ba44d8a2SVladimir Kotal	fi
373ba44d8a2SVladimir Kotal
374b0088928SVladimir Kotal	#
375ba44d8a2SVladimir Kotal	# Strip the ending slash.
376b0088928SVladimir Kotal	#
377ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
378ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
379ba44d8a2SVladimir Kotal	else
380ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
381ba44d8a2SVladimir Kotal	fi
382ba44d8a2SVladimir Kotal
383b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
384b0088928SVladimir Kotal		print "       Removing: \c"
385b0088928SVladimir Kotal	else
386b0088928SVladimir Kotal		print "rmdir \c"
387b0088928SVladimir Kotal	fi
388ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
389b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
390ba44d8a2SVladimir Kotal		return 1
391ba44d8a2SVladimir Kotal	fi
392ba44d8a2SVladimir Kotal
393b0088928SVladimir Kotal	#
394ba44d8a2SVladimir Kotal	# Prepare batch file.
395b0088928SVladimir Kotal	#
3968a34f8dcSVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
397ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
398b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
399ba44d8a2SVladimir Kotal		return 1
400ba44d8a2SVladimir Kotal	fi
401ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
402ba44d8a2SVladimir Kotal
403b0088928SVladimir Kotal	#
404ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
405b0088928SVladimir Kotal	#
4068a34f8dcSVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
407b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
408b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
409b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
410b0088928SVladimir Kotal		return 1
411b0088928SVladimir Kotal	fi
412b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
413ba44d8a2SVladimir Kotal	integer -r ret=$?
414ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
415ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
416b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
417b0088928SVladimir Kotal		print "error messages:"
418b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
419b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
420ba44d8a2SVladimir Kotal		return $ret
421ba44d8a2SVladimir Kotal	fi
422b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
423b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
424ba44d8a2SVladimir Kotal		print "Done."
425b0088928SVladimir Kotal	fi
426ba44d8a2SVladimir Kotal
427ba44d8a2SVladimir Kotal	return 0
428ba44d8a2SVladimir Kotal}
429ba44d8a2SVladimir Kotal
430ba44d8a2SVladimir Kotal#
43102d26c39SVladimir Kotal# Upload webrev to remote site
43202d26c39SVladimir Kotal#
433ba44d8a2SVladimir Kotalfunction upload_webrev
43402d26c39SVladimir Kotal{
435b0088928SVladimir Kotal	integer ret
43602d26c39SVladimir Kotal
43702d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
438b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
43902d26c39SVladimir Kotal		return 1
44002d26c39SVladimir Kotal	fi
44102d26c39SVladimir Kotal
442b0088928SVladimir Kotal	#
44302d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
44402d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
44502d26c39SVladimir Kotal	# target he probably knows what he is doing.
446b0088928SVladimir Kotal	#
44702d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
448ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
44902d26c39SVladimir Kotal			| $GREP closed >/dev/null
45002d26c39SVladimir Kotal		if (( $? == 0 )); then
451b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
452b0088928SVladimir Kotal			    "\"closed\" directory"
45302d26c39SVladimir Kotal			return 1
45402d26c39SVladimir Kotal		fi
45502d26c39SVladimir Kotal	fi
45602d26c39SVladimir Kotal
457b0088928SVladimir Kotal
458b0088928SVladimir Kotal	#
459b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
460b0088928SVladimir Kotal	#
46102d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
46202d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
463b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
464b0088928SVladimir Kotal			ret=$?
465b0088928SVladimir Kotal			return $ret
46602d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
46702d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
468b0088928SVladimir Kotal			ret=$?
469b0088928SVladimir Kotal			return $ret
47002d26c39SVladimir Kotal		fi
47102d26c39SVladimir Kotal	else
472b0088928SVladimir Kotal		#
473b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
474b0088928SVladimir Kotal		#
475b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
476b0088928SVladimir Kotal		ret=$?
477b0088928SVladimir Kotal		if (( $ret != 0 )); then
478b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
479ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
480b0088928SVladimir Kotal			ret=$?
48102d26c39SVladimir Kotal		fi
482b0088928SVladimir Kotal		return $ret
48302d26c39SVladimir Kotal	fi
48402d26c39SVladimir Kotal}
48502d26c39SVladimir Kotal
486daaffb31Sdp#
487371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
488371d72daSLubomir Sedlacik#
489371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
490371d72daSLubomir Sedlacik#
491371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
492371d72daSLubomir Sedlacik#
493371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
494371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
495371d72daSLubomir Sedlacik# a path delimiter.
496371d72daSLubomir Sedlacik#
49725cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make
49825cc4e45SVladimir Kotal# the substitution work with GNU sed.
49925cc4e45SVladimir Kotal#
500371d72daSLubomir Sedlacikfunction url_encode
501371d72daSLubomir Sedlacik{
502b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
503371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
504371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
505371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
50625cc4e45SVladimir Kotal	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
507371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
508371d72daSLubomir Sedlacik}
509371d72daSLubomir Sedlacik
510371d72daSLubomir Sedlacik#
511daaffb31Sdp# input_cmd | html_quote | output_cmd
512daaffb31Sdp# or
513daaffb31Sdp# html_quote filename | output_cmd
5147c478bd9Sstevel@tonic-gate#
5157c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5167c478bd9Sstevel@tonic-gate#
5177c478bd9Sstevel@tonic-gatehtml_quote()
5187c478bd9Sstevel@tonic-gate{
519b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5207c478bd9Sstevel@tonic-gate}
5217c478bd9Sstevel@tonic-gate
522daaffb31Sdp#
5238bcea973SRichard Lowe# Trim a digest-style revision to a conventionally readable yet useful length
5248bcea973SRichard Lowe#
5258bcea973SRichard Lowetrim_digest()
5268bcea973SRichard Lowe{
5278bcea973SRichard Lowe	typeset digest=$1
5288bcea973SRichard Lowe
5298bcea973SRichard Lowe	echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'
5308bcea973SRichard Lowe}
5318bcea973SRichard Lowe
5328bcea973SRichard Lowe#
5330fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
534daaffb31Sdp#
5350fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
5360fd2682eSMark J. Nelson# relevant databases.
537daaffb31Sdp#
5380fd2682eSMark J. Nelsonits2url()
5397c478bd9Sstevel@tonic-gate{
5400fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
541daaffb31Sdp}
542daaffb31Sdp
5437c478bd9Sstevel@tonic-gate#
544daaffb31Sdp# strip_unchanged <infile> | output_cmd
5457c478bd9Sstevel@tonic-gate#
546daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
547daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5487c478bd9Sstevel@tonic-gate#
549daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
550daaffb31Sdp# identical lines are retained before and after the changed lines to
551daaffb31Sdp# provide some context.  The number of these lines is controlled by the
552cdf0c1d5Smjnelson# variable C in the $AWK script below.
553daaffb31Sdp#
554daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
555daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
556daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
557daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
558daaffb31Sdp#
559daaffb31Sdpstrip_unchanged()
560daaffb31Sdp{
561cdf0c1d5Smjnelson	$AWK '
562daaffb31Sdp	BEGIN	{ C = c = 20 }
563cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
564daaffb31Sdp		if (c > C) {
565daaffb31Sdp			c -= C
566daaffb31Sdp			inx = 0
567daaffb31Sdp			if (c > C) {
568cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
569daaffb31Sdp				inx = c % C
570daaffb31Sdp				c = C
571daaffb31Sdp			}
572daaffb31Sdp
573daaffb31Sdp			for (i = 0; i < c; i++)
574daaffb31Sdp				print ln[(inx + i) % C]
575daaffb31Sdp		}
576daaffb31Sdp		c = 0;
577daaffb31Sdp		print
578daaffb31Sdp		next
579daaffb31Sdp	}
580daaffb31Sdp	{	if (c >= C) {
581daaffb31Sdp			ln[c % C] = $0
582daaffb31Sdp			c++;
583daaffb31Sdp			next;
584daaffb31Sdp		}
585daaffb31Sdp		c++;
586daaffb31Sdp		print
587daaffb31Sdp	}
588cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
589daaffb31Sdp
590daaffb31Sdp	' $1
591daaffb31Sdp}
592daaffb31Sdp
593daaffb31Sdp#
594daaffb31Sdp# sdiff_to_html
595daaffb31Sdp#
596daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
597daaffb31Sdp# processes the diff output to present the files as an HTML document with
598daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
599daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
600daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
601daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
602daaffb31Sdp# e.g.
603daaffb31Sdp#
604daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
605daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
606daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
607daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
608daaffb31Sdp#          1234567</a> my bugid' > <file>.html
609daaffb31Sdp#
610daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
611daaffb31Sdp# in the webrev tree.
612daaffb31Sdp#
613daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
614daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
615daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
616daaffb31Sdp# the editing codes, e.g.
6177c478bd9Sstevel@tonic-gate#
6187c478bd9Sstevel@tonic-gate#      8c8
6197c478bd9Sstevel@tonic-gate#      57a61
6207c478bd9Sstevel@tonic-gate#      63c66,76
6217c478bd9Sstevel@tonic-gate#      68,93d80
6227c478bd9Sstevel@tonic-gate#      106d90
6237c478bd9Sstevel@tonic-gate#      108,110d91
6247c478bd9Sstevel@tonic-gate#
625daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
626daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
627daaffb31Sdp#  into something like this:
6287c478bd9Sstevel@tonic-gate#
6297c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6307c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
631daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6327c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6337c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6347c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6357c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6367c478bd9Sstevel@tonic-gate#        :               :
6377c478bd9Sstevel@tonic-gate#
638daaffb31Sdp#  This script is then run on the original source file to generate the
639daaffb31Sdp#  HTML that corresponds to the source file.
6407c478bd9Sstevel@tonic-gate#
641daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
642daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
643daaffb31Sdp#  notice that the changes are color-coded:
6447c478bd9Sstevel@tonic-gate#
6457c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6467c478bd9Sstevel@tonic-gate#   blue      - changed lines
6477c478bd9Sstevel@tonic-gate#   bold blue - new lines
6487c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6497c478bd9Sstevel@tonic-gate#
650daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
651daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
652daaffb31Sdp#  Teamware's filemerge tool.
653daaffb31Sdp#
654daaffb31Sdpsdiff_to_html()
655daaffb31Sdp{
6567c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6577c478bd9Sstevel@tonic-gate
658daaffb31Sdp	TNAME=$3
659daaffb31Sdp	TPATH=$4
660daaffb31Sdp	COMMENT=$5
661daaffb31Sdp
6627c478bd9Sstevel@tonic-gate	#
6637c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6647c478bd9Sstevel@tonic-gate	#
665cdf0c1d5Smjnelson	$AWK '
6667c478bd9Sstevel@tonic-gate	BEGIN	{
6677c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
668daaffb31Sdp		printf "function removed() "
669daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
670daaffb31Sdp		printf "function changed() "
671daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
672daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6737c478bd9Sstevel@tonic-gate}
6747c478bd9Sstevel@tonic-gate	/^</	{next}
6757c478bd9Sstevel@tonic-gate	/^>/	{next}
6767c478bd9Sstevel@tonic-gate	/^---/	{next}
677daaffb31Sdp
6787c478bd9Sstevel@tonic-gate	{
6797c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6807c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6817c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6827c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6837c478bd9Sstevel@tonic-gate			if (n == 1)
6847c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6857c478bd9Sstevel@tonic-gate			else
6867c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6877c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6887c478bd9Sstevel@tonic-gate			next
6897c478bd9Sstevel@tonic-gate		}
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6927c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6937c478bd9Sstevel@tonic-gate		s = r[1];
6947c478bd9Sstevel@tonic-gate		if (n == 1)
6957c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6967c478bd9Sstevel@tonic-gate		else {
6977c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6987c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6997c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7007c478bd9Sstevel@tonic-gate		}
7017c478bd9Sstevel@tonic-gate		next
7027c478bd9Sstevel@tonic-gate	}
7037c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7047c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7057c478bd9Sstevel@tonic-gate		n1 = r[1]
7067c478bd9Sstevel@tonic-gate		n2 = r[2]
7077c478bd9Sstevel@tonic-gate		if (n == 1)
708daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
7097c478bd9Sstevel@tonic-gate		else
710daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
7117c478bd9Sstevel@tonic-gate		next
7127c478bd9Sstevel@tonic-gate	}
7137c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7147c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7157c478bd9Sstevel@tonic-gate		n1 = r[1]
7167c478bd9Sstevel@tonic-gate		n2 = r[2]
7177c478bd9Sstevel@tonic-gate		final = n2
7187c478bd9Sstevel@tonic-gate		d1 = 0
7197c478bd9Sstevel@tonic-gate		if (n == 1)
720daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7217c478bd9Sstevel@tonic-gate		else {
7227c478bd9Sstevel@tonic-gate			d1 = n2 - n1
723daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7247c478bd9Sstevel@tonic-gate		}
7257c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7267c478bd9Sstevel@tonic-gate		n1 = r[1]
7277c478bd9Sstevel@tonic-gate		n2 = r[2]
7287c478bd9Sstevel@tonic-gate		if (m > 1) {
7297c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7307c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7317c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7327c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7337c478bd9Sstevel@tonic-gate			}
7347c478bd9Sstevel@tonic-gate		}
7357c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate		next
7387c478bd9Sstevel@tonic-gate	}
7397c478bd9Sstevel@tonic-gate	}
7407c478bd9Sstevel@tonic-gate
741daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
742daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate	#
7457c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7467c478bd9Sstevel@tonic-gate	#
747cdf0c1d5Smjnelson	$AWK '
7487c478bd9Sstevel@tonic-gate	BEGIN	{
7497c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
750daaffb31Sdp		printf "function new() "
751daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
752daaffb31Sdp		printf "function changed() "
753daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
754daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7557c478bd9Sstevel@tonic-gate	}
756daaffb31Sdp
7577c478bd9Sstevel@tonic-gate	/^</	{next}
7587c478bd9Sstevel@tonic-gate	/^>/	{next}
7597c478bd9Sstevel@tonic-gate	/^---/	{next}
760daaffb31Sdp
7617c478bd9Sstevel@tonic-gate	{
7627c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7637c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7647c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7657c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7667c478bd9Sstevel@tonic-gate			if (n == 1)
7677c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7687c478bd9Sstevel@tonic-gate			else
7697c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7707c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7717c478bd9Sstevel@tonic-gate			next
7727c478bd9Sstevel@tonic-gate		}
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7757c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7767c478bd9Sstevel@tonic-gate		s = r[1];
7777c478bd9Sstevel@tonic-gate		if (n == 1)
7787c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7797c478bd9Sstevel@tonic-gate		else {
7807c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7817c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7827c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7837c478bd9Sstevel@tonic-gate		}
7847c478bd9Sstevel@tonic-gate		next
7857c478bd9Sstevel@tonic-gate	}
7867c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7877c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7887c478bd9Sstevel@tonic-gate		n1 = r[1]
7897c478bd9Sstevel@tonic-gate		n2 = r[2]
7907c478bd9Sstevel@tonic-gate		if (n == 1)
791daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7927c478bd9Sstevel@tonic-gate		else
793daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7947c478bd9Sstevel@tonic-gate		next
7957c478bd9Sstevel@tonic-gate	}
7967c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7977c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7987c478bd9Sstevel@tonic-gate		n1 = r[1]
7997c478bd9Sstevel@tonic-gate		n2 = r[2]
8007c478bd9Sstevel@tonic-gate		final = n2
8017c478bd9Sstevel@tonic-gate		d2 = 0;
8027c478bd9Sstevel@tonic-gate		if (n == 1) {
8037c478bd9Sstevel@tonic-gate			final = n1
804daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
8057c478bd9Sstevel@tonic-gate		} else {
8067c478bd9Sstevel@tonic-gate			d2 = n2 - n1
807daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
8087c478bd9Sstevel@tonic-gate		}
8097c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
8107c478bd9Sstevel@tonic-gate		n1 = r[1]
8117c478bd9Sstevel@tonic-gate		n2 = r[2]
8127c478bd9Sstevel@tonic-gate		if (m > 1) {
8137c478bd9Sstevel@tonic-gate			d1  = n2 - n1
8147c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8157c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8167c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8177c478bd9Sstevel@tonic-gate			}
8187c478bd9Sstevel@tonic-gate		}
8197c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8207c478bd9Sstevel@tonic-gate		next
8217c478bd9Sstevel@tonic-gate	}
8227c478bd9Sstevel@tonic-gate	}
823daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8247c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8257c478bd9Sstevel@tonic-gate
826daaffb31Sdp	#
827cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
828daaffb31Sdp	#
829cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8307c478bd9Sstevel@tonic-gate
831cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8327c478bd9Sstevel@tonic-gate
833daaffb31Sdp	#
834daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
835daaffb31Sdp	#
836daaffb31Sdp	print "$HTML<head>$STDHEAD"
837cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
838daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
839daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
840daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
841daaffb31Sdp	print "<table><tr valign=\"top\">"
842daaffb31Sdp	print "<td><pre>"
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8457c478bd9Sstevel@tonic-gate
846daaffb31Sdp	print "</pre></td><td><pre>"
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8497c478bd9Sstevel@tonic-gate
850daaffb31Sdp	print "</pre></td>"
851daaffb31Sdp	print "</tr></table>"
852daaffb31Sdp	print "</body></html>"
8537c478bd9Sstevel@tonic-gate
854daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
855daaffb31Sdp	    "$COMMENT"
8567c478bd9Sstevel@tonic-gate}
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate
859daaffb31Sdp#
860daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
861daaffb31Sdp#
862daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
863daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
864daaffb31Sdp# and then emit the main frame.  Content is placed into:
865daaffb31Sdp#
866daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
867daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
868daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
869daaffb31Sdp#
870daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
871daaffb31Sdp#
8727c478bd9Sstevel@tonic-gatefunction framed_sdiff
8737c478bd9Sstevel@tonic-gate{
8747c478bd9Sstevel@tonic-gate	typeset TNAME=$1
875daaffb31Sdp	typeset TPATH=$2
876daaffb31Sdp	typeset lhsfile=$3
877daaffb31Sdp	typeset rhsfile=$4
878daaffb31Sdp	typeset comments=$5
8797c478bd9Sstevel@tonic-gate	typeset RTOP
880daaffb31Sdp
8817c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
882daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
883daaffb31Sdp
884daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
885daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
886daaffb31Sdp
887daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8888b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8897c478bd9Sstevel@tonic-gate	    </head>
890daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
891cac38512Smjnelson	    <a name="0"></a>
892cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
893daaffb31Sdp	EOF
894daaffb31Sdp
895daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
896daaffb31Sdp
897daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
898daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
899daaffb31Sdp
900daaffb31Sdp	close='</body></html>'
901daaffb31Sdp
902daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
903daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
904daaffb31Sdp
905daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
906daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
907daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
908daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
909daaffb31Sdp	  <frameset rows="*,60">
910daaffb31Sdp	    <frameset cols="50%,50%">
911cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
912cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
913daaffb31Sdp	    </frameset>
9148b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
915cac38512Smjnelson	   marginheight="0" name="nav"></frame>
916daaffb31Sdp	  <noframes>
917daaffb31Sdp            <body id="SUNWwebrev">
918daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9197c478bd9Sstevel@tonic-gate	      and has the feature enabled.
920daaffb31Sdp            </body>
921daaffb31Sdp	  </noframes>
922daaffb31Sdp	  </frameset>
9237c478bd9Sstevel@tonic-gate	</html>
9247c478bd9Sstevel@tonic-gate	EOF
9257c478bd9Sstevel@tonic-gate}
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate
928daaffb31Sdp#
929daaffb31Sdp# fix_postscript
930daaffb31Sdp#
931daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
932daaffb31Sdp#	- removing all extraneous headers/trailers
933daaffb31Sdp#	- making the page numbers right
934daaffb31Sdp#	- removing pages devoid of contents which confuse some
935daaffb31Sdp#	  postscript readers.
936daaffb31Sdp#
937daaffb31Sdp# From Casper.
938daaffb31Sdp#
939daaffb31Sdpfunction fix_postscript
9407c478bd9Sstevel@tonic-gate{
941daaffb31Sdp	infile=$1
9427c478bd9Sstevel@tonic-gate
943daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9447c478bd9Sstevel@tonic-gate
945daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
946daaffb31Sdp	print "%%Orientation: Landscape\n";
9477c478bd9Sstevel@tonic-gate
948daaffb31Sdp	$pno = 0;
949daaffb31Sdp	$doprint = 1;
950daaffb31Sdp
951daaffb31Sdp	$page = "";
952daaffb31Sdp
953daaffb31Sdp	while (<>) {
954daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
955daaffb31Sdp
956daaffb31Sdp		if (/^%%Page:/) {
957daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
958daaffb31Sdp				# Header or single page containing text
959daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
960daaffb31Sdp				print $page;
961daaffb31Sdp				$pno++;
962daaffb31Sdp			} else {
963daaffb31Sdp				# Empty page, skip it.
9647c478bd9Sstevel@tonic-gate			}
965daaffb31Sdp			$page = "";
966daaffb31Sdp			$doprint = 1;
9677c478bd9Sstevel@tonic-gate			next;
9687c478bd9Sstevel@tonic-gate		}
9697c478bd9Sstevel@tonic-gate
970daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
971daaffb31Sdp		# %%Page of the next
972daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
973daaffb31Sdp		$page .= $_ if ($doprint);
9747c478bd9Sstevel@tonic-gate	}
9757c478bd9Sstevel@tonic-gate
976daaffb31Sdp	if ($page =~ /\)S/) {
977daaffb31Sdp		print "%%Page: ? $pno\n";
978daaffb31Sdp		print $page;
979daaffb31Sdp	} else {
980daaffb31Sdp		$pno--;
981daaffb31Sdp	}
982daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
983daaffb31SdpEOF
984daaffb31Sdp
98514983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
986daaffb31Sdp}
987daaffb31Sdp
988daaffb31Sdp
989daaffb31Sdp#
990daaffb31Sdp# input_cmd | insert_anchors | output_cmd
991daaffb31Sdp#
9927c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
993daaffb31Sdp# anchors.  These are used to drive the frames version of the
9947c478bd9Sstevel@tonic-gate# sdiffs output.
9957c478bd9Sstevel@tonic-gate#
9967c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9977c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9987c478bd9Sstevel@tonic-gate#
999daaffb31Sdp# The script detects changed lines as any line that has a "<span
1000daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
1001daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
10027c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
10037c478bd9Sstevel@tonic-gate# deleted.
10047c478bd9Sstevel@tonic-gate#
1005daaffb31Sdpfunction insert_anchors
1006daaffb31Sdp{
1007cdf0c1d5Smjnelson	$AWK '
10087c478bd9Sstevel@tonic-gate	function ia() {
1009daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
10107c478bd9Sstevel@tonic-gate	}
1011daaffb31Sdp
10127c478bd9Sstevel@tonic-gate	BEGIN {
1013daaffb31Sdp		anc=1;
10147c478bd9Sstevel@tonic-gate		inblock=1;
1015daaffb31Sdp		printf "<pre>\n";
10167c478bd9Sstevel@tonic-gate	}
1017daaffb31Sdp	NF == 0 || /^<span class=/ {
10187c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10197c478bd9Sstevel@tonic-gate			ia();
10207c478bd9Sstevel@tonic-gate			inblock=1;
10217c478bd9Sstevel@tonic-gate		}
10227c478bd9Sstevel@tonic-gate		print;
10237c478bd9Sstevel@tonic-gate		next;
10247c478bd9Sstevel@tonic-gate	}
10257c478bd9Sstevel@tonic-gate	{
10267c478bd9Sstevel@tonic-gate		inblock=0;
10277c478bd9Sstevel@tonic-gate		print;
10287c478bd9Sstevel@tonic-gate	}
10297c478bd9Sstevel@tonic-gate	END {
10307c478bd9Sstevel@tonic-gate		ia();
1031daaffb31Sdp
1032daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1033daaffb31Sdp		printf "--- EOF ---</b>"
10347c478bd9Sstevel@tonic-gate		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1035daaffb31Sdp		printf "</pre>"
1036daaffb31Sdp		printf "<form name=\"eof\">";
1037cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1038cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1039daaffb31Sdp		printf "</form>";
10407c478bd9Sstevel@tonic-gate	}
10417c478bd9Sstevel@tonic-gate	' $1
10427c478bd9Sstevel@tonic-gate}
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate
1045daaffb31Sdp#
1046daaffb31Sdp# relative_dir
1047daaffb31Sdp#
1048daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1049daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1050daaffb31Sdp# this function would print "../../../../".
1051daaffb31Sdp#
1052daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1053daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1054daaffb31Sdp# is not relocatable.
1055daaffb31Sdp#
1056daaffb31Sdpfunction relative_dir
10577c478bd9Sstevel@tonic-gate{
1058daaffb31Sdp        typeset cur="${1##$2?(/)}"
10598b3b7b16SMark J. Nelson
10608b3b7b16SMark J. Nelson        #
10618b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
10628b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
10638b3b7b16SMark J. Nelson        #
10640fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1065daaffb31Sdp                # Should never happen.
106614983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1067daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1068daaffb31Sdp                print -u2 "will not be relocatable!"
1069daaffb31Sdp                print $2
1070daaffb31Sdp                return
1071daaffb31Sdp        fi
1072daaffb31Sdp
10738b3b7b16SMark J. Nelson	#
10748b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
10758b3b7b16SMark J. Nelson	#
10768b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
10778b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
10788b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
10798b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
10808b3b7b16SMark J. Nelson	#    the end of a relative path.
10818b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
10828b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
10838b3b7b16SMark J. Nelson	#    level of relative separation.
10848b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
10858b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
10868b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
10878b3b7b16SMark J. Nelson	#
10880fd2682eSMark J. Nelson	print $cur | $SED -e '{
10898b3b7b16SMark J. Nelson		s:^\./*::
10908b3b7b16SMark J. Nelson		s:/$::
10918b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
10920fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
10930fd2682eSMark J. Nelson	}'
10947c478bd9Sstevel@tonic-gate}
10957c478bd9Sstevel@tonic-gate
1096daaffb31Sdp#
1097daaffb31Sdp# frame_nav_js
1098daaffb31Sdp#
1099daaffb31Sdp# Emit javascript for frame navigation
1100daaffb31Sdp#
1101daaffb31Sdpfunction frame_nav_js
11027c478bd9Sstevel@tonic-gate{
11037c478bd9Sstevel@tonic-gatecat << \EOF
11047c478bd9Sstevel@tonic-gatevar myInt;
11057c478bd9Sstevel@tonic-gatevar scrolling=0;
1106daaffb31Sdpvar sfactor = 3;
11077c478bd9Sstevel@tonic-gatevar scount=10;
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gatefunction scrollByPix() {
11107c478bd9Sstevel@tonic-gate	if (scount<=0) {
11117c478bd9Sstevel@tonic-gate		sfactor*=1.2;
11127c478bd9Sstevel@tonic-gate		scount=10;
11137c478bd9Sstevel@tonic-gate	}
11147c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11157c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11167c478bd9Sstevel@tonic-gate	scount--;
11177c478bd9Sstevel@tonic-gate}
11187c478bd9Sstevel@tonic-gate
1119daaffb31Sdpfunction scrollToAnc(num) {
1120daaffb31Sdp
1121daaffb31Sdp	// Update the value of the anchor in the form which we use as
1122daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1123daaffb31Sdp	// correcting for overflow and underflow of the value and return
1124daaffb31Sdp	// us the new value.
1125daaffb31Sdp	num = setAncValue(num);
1126daaffb31Sdp
1127daaffb31Sdp	// Set location and scroll back a little to expose previous
1128daaffb31Sdp	// lines.
1129daaffb31Sdp	//
1130daaffb31Sdp	// Note that this could be improved: it is possible although
1131daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1132daaffb31Sdp	// scroll to that location directly.
1133daaffb31Sdp	//
11347c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11357c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1136daaffb31Sdp
11377c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11387c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11397c478bd9Sstevel@tonic-gate}
11407c478bd9Sstevel@tonic-gate
1141daaffb31Sdpfunction getAncValue()
1142daaffb31Sdp{
1143daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1144daaffb31Sdp}
1145daaffb31Sdp
1146daaffb31Sdpfunction setAncValue(val)
1147daaffb31Sdp{
1148daaffb31Sdp	if (val <= 0) {
1149daaffb31Sdp		val = 0;
1150daaffb31Sdp		parent.nav.document.diff.real.value = val;
1151daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1152daaffb31Sdp		return (val);
1153daaffb31Sdp	}
1154daaffb31Sdp
1155daaffb31Sdp	//
1156daaffb31Sdp	// The way we compute the max anchor value is to stash it
1157daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1158daaffb31Sdp	// on each side, so we pluck from the left.
1159daaffb31Sdp	//
1160daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1161daaffb31Sdp	if (val < maxval) {
1162daaffb31Sdp		parent.nav.document.diff.real.value = val;
1163daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1164daaffb31Sdp		return (val);
1165daaffb31Sdp	}
1166daaffb31Sdp
1167daaffb31Sdp	// this must be: val >= maxval
1168daaffb31Sdp	val = maxval;
1169daaffb31Sdp	parent.nav.document.diff.real.value = val;
1170daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1171daaffb31Sdp	return (val);
1172daaffb31Sdp}
1173daaffb31Sdp
11747c478bd9Sstevel@tonic-gatefunction stopScroll() {
11757c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11767c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11777c478bd9Sstevel@tonic-gate		scrolling=0;
11787c478bd9Sstevel@tonic-gate	}
11797c478bd9Sstevel@tonic-gate}
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gatefunction startScroll() {
11827c478bd9Sstevel@tonic-gate	stopScroll();
11837c478bd9Sstevel@tonic-gate	scrolling=1;
11847c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11857c478bd9Sstevel@tonic-gate}
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1188daaffb31Sdp
11897c478bd9Sstevel@tonic-gate	switch (b) {
11907c478bd9Sstevel@tonic-gate	    case 1 :
1191daaffb31Sdp		scrollToAnc(-1);
11927c478bd9Sstevel@tonic-gate		break;
11937c478bd9Sstevel@tonic-gate	    case 2 :
1194daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11957c478bd9Sstevel@tonic-gate		break;
11967c478bd9Sstevel@tonic-gate	    case 3 :
11977c478bd9Sstevel@tonic-gate		sfactor=-3;
11987c478bd9Sstevel@tonic-gate		startScroll();
11997c478bd9Sstevel@tonic-gate		break;
12007c478bd9Sstevel@tonic-gate	    case 4 :
12017c478bd9Sstevel@tonic-gate		sfactor=3;
12027c478bd9Sstevel@tonic-gate		startScroll();
12037c478bd9Sstevel@tonic-gate		break;
12047c478bd9Sstevel@tonic-gate	    case 5 :
1205daaffb31Sdp		scrollToAnc(getAncValue() + 1);
12067c478bd9Sstevel@tonic-gate		break;
12077c478bd9Sstevel@tonic-gate	    case 6 :
1208daaffb31Sdp		scrollToAnc(999999);
12097c478bd9Sstevel@tonic-gate		break;
12107c478bd9Sstevel@tonic-gate	}
12117c478bd9Sstevel@tonic-gate}
12127c478bd9Sstevel@tonic-gate
12137c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
12147c478bd9Sstevel@tonic-gate	stopScroll();
12157c478bd9Sstevel@tonic-gate}
12167c478bd9Sstevel@tonic-gate
1217daaffb31Sdpfunction keypress(ev) {
1218daaffb31Sdp	var keynum;
1219daaffb31Sdp	var keychar;
1220daaffb31Sdp
1221daaffb31Sdp	if (window.event) { // IE
1222daaffb31Sdp		keynum = ev.keyCode;
1223daaffb31Sdp	} else if (ev.which) { // non-IE
1224daaffb31Sdp		keynum = ev.which;
1225daaffb31Sdp	}
1226daaffb31Sdp
1227daaffb31Sdp	keychar = String.fromCharCode(keynum);
1228daaffb31Sdp
1229daaffb31Sdp	if (keychar == "k") {
1230daaffb31Sdp		handlePress(2);
1231daaffb31Sdp		return (0);
1232daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1233daaffb31Sdp		handlePress(5);
1234daaffb31Sdp		return (0);
1235daaffb31Sdp	}
1236daaffb31Sdp	return (1);
1237daaffb31Sdp}
1238daaffb31Sdp
12397c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1240daaffb31Sdp	val = parent.nav.document.diff.display.value;
1241daaffb31Sdp	if (val == "EOF") {
1242daaffb31Sdp		scrollToAnc(999999);
1243daaffb31Sdp		return;
1244daaffb31Sdp	}
1245daaffb31Sdp
1246daaffb31Sdp	if (val == "BOF") {
1247daaffb31Sdp		scrollToAnc(0);
1248daaffb31Sdp		return;
1249daaffb31Sdp	}
1250daaffb31Sdp
1251daaffb31Sdp        i=parseInt(val);
12527c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1253daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12547c478bd9Sstevel@tonic-gate        } else {
1255daaffb31Sdp                scrollToAnc(i);
12567c478bd9Sstevel@tonic-gate        }
12577c478bd9Sstevel@tonic-gate        return false;
12587c478bd9Sstevel@tonic-gate}
12597c478bd9Sstevel@tonic-gate
1260daaffb31SdpEOF
1261daaffb31Sdp}
1262daaffb31Sdp
1263daaffb31Sdp#
1264daaffb31Sdp# frame_navigation
1265daaffb31Sdp#
1266daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1267daaffb31Sdp#
1268daaffb31Sdpfunction frame_navigation
1269daaffb31Sdp{
1270daaffb31Sdp	print "$HTML<head>$STDHEAD"
1271daaffb31Sdp
1272daaffb31Sdp	cat << \EOF
1273daaffb31Sdp<title>Anchor Navigation</title>
1274daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1275daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1276daaffb31Sdp
1277daaffb31Sdp<style type="text/css">
1278daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1279daaffb31Sdp		    background-color: #eee; text-align: center;
1280daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1281daaffb31Sdp    div.button a { font-weight: bold; color: black }
1282daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1283daaffb31Sdp</style>
1284daaffb31SdpEOF
1285daaffb31Sdp
1286cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1287daaffb31Sdp
1288daaffb31Sdp	cat << \EOF
12897c478bd9Sstevel@tonic-gate</head>
1290daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1291daaffb31Sdp	onkeypress="keypress(event);">
12927c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12937c478bd9Sstevel@tonic-gate      <center>
1294cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12957c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12967c478bd9Sstevel@tonic-gate      </center>
12977c478bd9Sstevel@tonic-gate    </noscript>
12987c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1299daaffb31Sdp	<tr>
1300daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1301daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1302daaffb31Sdp          at right</td>
1303daaffb31Sdp	  <td align="center" valign="top" width="50%">
13047c478bd9Sstevel@tonic-gate	    <div class="button">
1305daaffb31Sdp	      <table border="0" align="center">
1306daaffb31Sdp                  <tr>
1307daaffb31Sdp		    <td>
13087c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
13097c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
13107c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
13117c478bd9Sstevel@tonic-gate			 onClick="return false;"
13127c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1313daaffb31Sdp		    <td>
13147c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13157c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13167c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13177c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1318daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1319daaffb31Sdp		    <td>
13207c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13217c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13227c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13237c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13247c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13257c478bd9Sstevel@tonic-gate		    </td></tr>
1326daaffb31Sdp
13277c478bd9Sstevel@tonic-gate		  <tr>
1328daaffb31Sdp		    <td>
13297c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13307c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13317c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13327c478bd9Sstevel@tonic-gate			 onClick="return false;"
13337c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1334daaffb31Sdp		    <td>
13357c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13367c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13377c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13387c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1339daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1340daaffb31Sdp		    <td>
13417c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13427c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13437c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13447c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13457c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1346daaffb31Sdp		  </tr>
1347daaffb31Sdp              </table>
1348daaffb31Sdp	    </div>
1349daaffb31Sdp	  </td>
13507c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1351daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1352cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1353cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13547c478bd9Sstevel@tonic-gate	    </form>
13557c478bd9Sstevel@tonic-gate	  </th>
1356daaffb31Sdp	</tr>
13577c478bd9Sstevel@tonic-gate    </table>
13587c478bd9Sstevel@tonic-gate  </body>
13597c478bd9Sstevel@tonic-gate</html>
13607c478bd9Sstevel@tonic-gateEOF
13617c478bd9Sstevel@tonic-gate}
13627c478bd9Sstevel@tonic-gate
13637c478bd9Sstevel@tonic-gate
1364daaffb31Sdp
1365daaffb31Sdp#
1366daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1367daaffb31Sdp#
1368daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1369daaffb31Sdp# context or unified diffs.
1370daaffb31Sdp#
13717c478bd9Sstevel@tonic-gatediff_to_html()
13727c478bd9Sstevel@tonic-gate{
13737c478bd9Sstevel@tonic-gate	TNAME=$1
1374daaffb31Sdp	TPATH=$2
1375daaffb31Sdp	DIFFTYPE=$3
1376daaffb31Sdp	COMMENT=$4
1377daaffb31Sdp
1378daaffb31Sdp	print "$HTML<head>$STDHEAD"
1379daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1380daaffb31Sdp
1381daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1382daaffb31Sdp		print "$UDIFFCSS"
1383daaffb31Sdp	fi
1384daaffb31Sdp
1385daaffb31Sdp	cat <<-EOF
1386daaffb31Sdp	</head>
1387daaffb31Sdp	<body id="SUNWwebrev">
1388daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1389daaffb31Sdp	<pre>$COMMENT</pre>
1390daaffb31Sdp        <pre>
1391daaffb31Sdp	EOF
13927c478bd9Sstevel@tonic-gate
1393cdf0c1d5Smjnelson	html_quote | $AWK '
1394daaffb31Sdp	/^--- new/	{ next }
1395daaffb31Sdp	/^\+\+\+ new/	{ next }
1396daaffb31Sdp	/^--- old/	{ next }
1397daaffb31Sdp	/^\*\*\* old/	{ next }
1398daaffb31Sdp	/^\*\*\*\*/	{ next }
13997c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1400cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1401daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1402daaffb31Sdp			  next}
1403daaffb31Sdp
1404cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1405daaffb31Sdp			  next}
1406daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1407daaffb31Sdp			  next}
1408daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1409daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1410daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1411daaffb31Sdp			{printf "%s\n", $0; next}
14127c478bd9Sstevel@tonic-gate	'
1413daaffb31Sdp
1414daaffb31Sdp	print "</pre></body></html>\n"
14157c478bd9Sstevel@tonic-gate}
14167c478bd9Sstevel@tonic-gate
14177c478bd9Sstevel@tonic-gate
1418daaffb31Sdp#
1419daaffb31Sdp# source_to_html { new | old } <filename>
1420daaffb31Sdp#
1421daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1422daaffb31Sdp#
14237c478bd9Sstevel@tonic-gatesource_to_html()
14247c478bd9Sstevel@tonic-gate{
14257c478bd9Sstevel@tonic-gate	WHICH=$1
14267c478bd9Sstevel@tonic-gate	TNAME=$2
14277c478bd9Sstevel@tonic-gate
1428daaffb31Sdp	print "$HTML<head>$STDHEAD"
1429cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1430daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1431daaffb31Sdp	print "<pre>"
1432cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1433daaffb31Sdp	print "</pre></body></html>"
14347c478bd9Sstevel@tonic-gate}
14357c478bd9Sstevel@tonic-gate
1436daaffb31Sdp#
1437cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1438daaffb31Sdp#
1439cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1440cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1441cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1442cdf0c1d5Smjnelson# are turned into URLs.
1443cdf0c1d5Smjnelson#
1444cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1445daaffb31Sdp#
1446daaffb31Sdpcomments_from_wx()
14477c478bd9Sstevel@tonic-gate{
1448daaffb31Sdp	typeset fmt=$1
1449daaffb31Sdp	typeset p=$2
14507c478bd9Sstevel@tonic-gate
1451cdf0c1d5Smjnelson	comm=`$AWK '
1452daaffb31Sdp	$1 == "'$p'" {
14537c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
14547c478bd9Sstevel@tonic-gate		getline
14557c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
14567c478bd9Sstevel@tonic-gate		exit
1457daaffb31Sdp	}' < $wxfile`
1458daaffb31Sdp
1459cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1460cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1461cdf0c1d5Smjnelson	fi
1462cdf0c1d5Smjnelson
1463daaffb31Sdp	if [[ $fmt == "text" ]]; then
1464cdf0c1d5Smjnelson		print -- "$comm"
1465daaffb31Sdp		return
1466daaffb31Sdp	fi
1467daaffb31Sdp
14680fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1469cdf0c1d5Smjnelson
14707c478bd9Sstevel@tonic-gate}
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate#
1473daaffb31Sdp# getcomments {text|html} filepath parentpath
1474daaffb31Sdp#
1475daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1476daaffb31Sdp#
1477daaffb31Sdpgetcomments()
1478daaffb31Sdp{
1479daaffb31Sdp	typeset fmt=$1
1480daaffb31Sdp	typeset p=$2
1481daaffb31Sdp	typeset pp=$3
14827c478bd9Sstevel@tonic-gate
14833df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
14843df69ef3SDarren Moffat		return
14853df69ef3SDarren Moffat	fi
1486cdf0c1d5Smjnelson	#
1487cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1488cdf0c1d5Smjnelson	# will be used there, too
1489cdf0c1d5Smjnelson	#
1490daaffb31Sdp	if [[ -n $wxfile ]]; then
1491daaffb31Sdp		comments_from_wx $fmt $p
1492daaffb31Sdp	fi
1493daaffb31Sdp}
1494daaffb31Sdp
1495daaffb31Sdp#
1496daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1497daaffb31Sdp#
1498daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1499daaffb31Sdp#
1500daaffb31Sdpfunction printCI
1501daaffb31Sdp{
1502daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1503daaffb31Sdp	typeset str
1504daaffb31Sdp	if (( tot == 1 )); then
1505daaffb31Sdp		str="line"
1506daaffb31Sdp	else
1507daaffb31Sdp		str="lines"
1508daaffb31Sdp	fi
1509daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1510daaffb31Sdp	    $tot $str $ins $del $mod $unc
1511daaffb31Sdp}
1512daaffb31Sdp
1513daaffb31Sdp
1514daaffb31Sdp#
1515daaffb31Sdp# difflines <oldfile> <newfile>
1516daaffb31Sdp#
1517daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1518daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1519daaffb31Sdp#
15207c478bd9Sstevel@tonic-gatefunction difflines
15217c478bd9Sstevel@tonic-gate{
1522daaffb31Sdp	integer tot mod del ins unc err
15237c478bd9Sstevel@tonic-gate	typeset filename
15247c478bd9Sstevel@tonic-gate
1525cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1526daaffb31Sdp	# Change range of lines: N,Nc
15277c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15287c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15297c478bd9Sstevel@tonic-gate		if (n != 2) {
15307c478bd9Sstevel@tonic-gate		    error=2
15317c478bd9Sstevel@tonic-gate		    exit;
15327c478bd9Sstevel@tonic-gate		}
1533daaffb31Sdp		#
1534daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1535daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1536daaffb31Sdp		#
15377c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1538daaffb31Sdp
1539daaffb31Sdp		#
1540daaffb31Sdp		# Now count replacement lines: each represents a change instead
1541daaffb31Sdp		# of a delete, so increment c and decrement r.
1542daaffb31Sdp		#
15437c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15447c478bd9Sstevel@tonic-gate			c++;
15457c478bd9Sstevel@tonic-gate			r--;
15467c478bd9Sstevel@tonic-gate		}
1547daaffb31Sdp		#
1548daaffb31Sdp		# If there were more replacement lines than original lines,
1549daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1550daaffb31Sdp		# but there are r changes that should be counted as adds, and
1551daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1552daaffb31Sdp		#
15537c478bd9Sstevel@tonic-gate		if (r < 0) {
15547c478bd9Sstevel@tonic-gate			a-=r;
15557c478bd9Sstevel@tonic-gate			c+=r;
15567c478bd9Sstevel@tonic-gate		}
1557daaffb31Sdp
1558daaffb31Sdp		#
1559daaffb31Sdp		# If there were more original lines than replacement lines, then
1560daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1561daaffb31Sdp		#
15627c478bd9Sstevel@tonic-gate		if (r > 0) {
15637c478bd9Sstevel@tonic-gate			d+=r;
15647c478bd9Sstevel@tonic-gate		}
15657c478bd9Sstevel@tonic-gate		next;
15667c478bd9Sstevel@tonic-gate	}
15677c478bd9Sstevel@tonic-gate
1568daaffb31Sdp	# Change lines: Nc
15697c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1570daaffb31Sdp		# The first line is a replacement; any more are additions.
15717c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
15727c478bd9Sstevel@tonic-gate			c++;
15737c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
15747c478bd9Sstevel@tonic-gate		}
15757c478bd9Sstevel@tonic-gate		next;
15767c478bd9Sstevel@tonic-gate	}
15777c478bd9Sstevel@tonic-gate
1578daaffb31Sdp	# Add lines: both Na and N,Na
15797c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
15807c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
15817c478bd9Sstevel@tonic-gate		next;
15827c478bd9Sstevel@tonic-gate	}
15837c478bd9Sstevel@tonic-gate
1584daaffb31Sdp	# Delete range of lines: N,Nd
15857c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
15867c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15877c478bd9Sstevel@tonic-gate		if (n != 2) {
15887c478bd9Sstevel@tonic-gate			error=2
15897c478bd9Sstevel@tonic-gate			exit;
15907c478bd9Sstevel@tonic-gate		}
1591daaffb31Sdp		#
1592daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1593daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1594daaffb31Sdp		#
15957c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
15967c478bd9Sstevel@tonic-gate		d+=r;
15977c478bd9Sstevel@tonic-gate		next;
15987c478bd9Sstevel@tonic-gate	}
15997c478bd9Sstevel@tonic-gate
1600daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16017c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16027c478bd9Sstevel@tonic-gate
1603daaffb31Sdp	# Should not get here!
16047c478bd9Sstevel@tonic-gate	{
16057c478bd9Sstevel@tonic-gate		error=1;
16067c478bd9Sstevel@tonic-gate		exit;
16077c478bd9Sstevel@tonic-gate	}
16087c478bd9Sstevel@tonic-gate
1609daaffb31Sdp	# Finish off - print results
16107c478bd9Sstevel@tonic-gate	END {
1611daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16127c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16137c478bd9Sstevel@tonic-gate	}' )
16147c478bd9Sstevel@tonic-gate
1615cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16167c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1617daaffb31Sdp		print "Unexpected Error occurred reading" \
1618daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1619daaffb31Sdp		return
1620daaffb31Sdp	fi
1621daaffb31Sdp
16227c478bd9Sstevel@tonic-gate	# Accumulate totals
16237c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1624daaffb31Sdp	(( TMOD += mod ))
16257c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16267c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16277c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1628cdf0c1d5Smjnelson	unc=`wc -l < $1`
16297c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1630daaffb31Sdp		(( unc -= del + mod ))
16317c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16327c478bd9Sstevel@tonic-gate	fi
16337c478bd9Sstevel@tonic-gate	# print summary
1634daaffb31Sdp	print "<span class=\"lineschanged\">"
1635daaffb31Sdp	printCI $tot $ins $del $mod $unc
1636daaffb31Sdp	print "</span>"
16377c478bd9Sstevel@tonic-gate}
16387c478bd9Sstevel@tonic-gate
1639daaffb31Sdp
16407c478bd9Sstevel@tonic-gate#
1641daaffb31Sdp# flist_from_wx
1642daaffb31Sdp#
1643daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1644daaffb31Sdp# Sets the global 'wxfile' variable.
1645daaffb31Sdp#
1646daaffb31Sdpfunction flist_from_wx
16477c478bd9Sstevel@tonic-gate{
1648daaffb31Sdp	typeset argfile=$1
1649daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1650daaffb31Sdp		#
1651daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1652daaffb31Sdp		# because the webrev does a "cd" later on.
1653daaffb31Sdp		#
1654daaffb31Sdp		wxfile=$PWD/$argfile
16557c478bd9Sstevel@tonic-gate	else
1656daaffb31Sdp		wxfile=$argfile
16577c478bd9Sstevel@tonic-gate	fi
16587c478bd9Sstevel@tonic-gate
1659cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
16607c478bd9Sstevel@tonic-gate	  while (getline) {
16617c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
16627c478bd9Sstevel@tonic-gate		if (c > 0) print
16637c478bd9Sstevel@tonic-gate	  }
1664daaffb31Sdp	}' $wxfile > $FLIST
16657c478bd9Sstevel@tonic-gate
1666daaffb31Sdp	print " Done."
1667daaffb31Sdp}
16687c478bd9Sstevel@tonic-gate
1669daaffb31Sdp#
1670cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1671cdf0c1d5Smjnelson#
1672cdf0c1d5Smjnelsonfunction hg_active_wxfile
1673cdf0c1d5Smjnelson{
1674cdf0c1d5Smjnelson	typeset child=$1
1675cdf0c1d5Smjnelson	typeset parent=$2
1676cdf0c1d5Smjnelson
1677cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
16789a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1679cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1680cdf0c1d5Smjnelson}
1681cdf0c1d5Smjnelson
1682cdf0c1d5Smjnelson#
1683cdf0c1d5Smjnelson# flist_from_mercurial
1684cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1685cdf0c1d5Smjnelson# flist_from_wx
1686cdf0c1d5Smjnelson#
1687cdf0c1d5Smjnelsonfunction flist_from_mercurial
1688cdf0c1d5Smjnelson{
1689cdf0c1d5Smjnelson	typeset child=$1
1690cdf0c1d5Smjnelson	typeset parent=$2
1691cdf0c1d5Smjnelson
1692cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1693cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1694cdf0c1d5Smjnelson		print		# Blank line for the \c above
1695cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1696cdf0c1d5Smjnelson		exit 1
1697cdf0c1d5Smjnelson	fi
1698cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1699cdf0c1d5Smjnelson
1700cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1701cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1702cdf0c1d5Smjnelson}
1703cdf0c1d5Smjnelson
1704cdf0c1d5Smjnelson#
17058bcea973SRichard Lowe# Transform a specified 'git log' output format into a wx-like active list.
17068bcea973SRichard Lowe#
17078bcea973SRichard Lowefunction git_wxfile
17088bcea973SRichard Lowe{
17098bcea973SRichard Lowe	typeset child="$1"
17108bcea973SRichard Lowe	typeset parent="$2"
17118bcea973SRichard Lowe
17128bcea973SRichard Lowe	TMPFLIST=/tmp/$$.active
17138bcea973SRichard Lowe	$PERL -e 'my (%files, %realfiles, $msg);
17148bcea973SRichard Lowe	my $branch = $ARGV[0];
17158bcea973SRichard Lowe
17168bcea973SRichard Lowe	open(F, "git diff -M --name-status $branch |");
17178bcea973SRichard Lowe	while (<F>) {
17188bcea973SRichard Lowe	    chomp;
17198bcea973SRichard Lowe	    if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
17208bcea973SRichard Lowe		if ($1 >= 75) {			 # Probably worth treating as a rename
17213cb02613SRichard Lowe		    $realfiles{$3} = $2;
17228bcea973SRichard Lowe		} else {
17238bcea973SRichard Lowe		    $realfiles{$3} = $3;
17248bcea973SRichard Lowe		    $realfiles{$2} = $2;
17258bcea973SRichard Lowe	        }
17268bcea973SRichard Lowe	    } else {
17278bcea973SRichard Lowe		my $f = (split /\s+/, $_)[1];
17288bcea973SRichard Lowe		$realfiles{$f} = $f;
17298bcea973SRichard Lowe	    }
17308bcea973SRichard Lowe	}
17318bcea973SRichard Lowe	close(F);
17328bcea973SRichard Lowe
17338bcea973SRichard Lowe	my $state = 1;		    # 0|comments, 1|files
17348bcea973SRichard Lowe	open(F, "git whatchanged --pretty=format:%B $branch.. |");
17358bcea973SRichard Lowe	while (<F>) {
17368bcea973SRichard Lowe	    chomp;
17378bcea973SRichard Lowe	    if (/^:[0-9]{6}/) {
17388bcea973SRichard Lowe		my $fname = (split /\t/, $_)[1];
17398bcea973SRichard Lowe		next if !defined($realfiles{$fname}); # No real change
17408bcea973SRichard Lowe		$state = 1;
17413cb02613SRichard Lowe		chomp $msg;
17423cb02613SRichard Lowe		$files{$fname} .= $msg;
17438bcea973SRichard Lowe	    } else {
17448bcea973SRichard Lowe		if ($state == 1) {
17458bcea973SRichard Lowe		    $state = 0;
17468bcea973SRichard Lowe		    $msg = /^\n/ ? "" : "\n";
17478bcea973SRichard Lowe		}
17488bcea973SRichard Lowe		$msg .= "$_\n" if ($_);
17498bcea973SRichard Lowe	    }
17508bcea973SRichard Lowe	}
17518bcea973SRichard Lowe	close(F);
17528bcea973SRichard Lowe
17538bcea973SRichard Lowe	for (sort keys %files) {
17548bcea973SRichard Lowe	    if ($realfiles{$_} ne $_) {
17553cb02613SRichard Lowe		print "$_ $realfiles{$_}\n$files{$_}\n\n";
17568bcea973SRichard Lowe	    } else {
17573cb02613SRichard Lowe		print "$_\n$files{$_}\n\n"
17588bcea973SRichard Lowe	    }
17598bcea973SRichard Lowe	}' ${parent} > $TMPFLIST
17608bcea973SRichard Lowe
17618bcea973SRichard Lowe	wxfile=$TMPFLIST
17628bcea973SRichard Lowe}
17638bcea973SRichard Lowe
17648bcea973SRichard Lowe#
17658bcea973SRichard Lowe# flist_from_git
17668bcea973SRichard Lowe# Build a wx-style active list, and hand it off to flist_from_wx
17678bcea973SRichard Lowe#
17688bcea973SRichard Lowefunction flist_from_git
17698bcea973SRichard Lowe{
17708bcea973SRichard Lowe	typeset child=$1
17718bcea973SRichard Lowe	typeset parent=$2
17728bcea973SRichard Lowe
17738bcea973SRichard Lowe	print " File list from: git ...\c"
17748bcea973SRichard Lowe	git_wxfile "$child" "$parent";
17758bcea973SRichard Lowe
17768bcea973SRichard Lowe	# flist_from_wx prints the Done, so we don't have to.
17778bcea973SRichard Lowe	flist_from_wx $TMPFLIST
17788bcea973SRichard Lowe}
17798bcea973SRichard Lowe
17808bcea973SRichard Lowe#
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
1830d7b56f41SBart Coddens	ppath=$ppath:/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_mercurial
1853cdf0c1d5Smjnelson{
1854cdf0c1d5Smjnelson	typeset olddir="$1"
1855cdf0c1d5Smjnelson	typeset newdir="$2"
1856cdf0c1d5Smjnelson	typeset old_mode=
1857cdf0c1d5Smjnelson	typeset new_mode=
1858cdf0c1d5Smjnelson	typeset file
1859cdf0c1d5Smjnelson
1860cdf0c1d5Smjnelson	#
1861cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1862cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1863cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1864cdf0c1d5Smjnelson	#
1865cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1866cdf0c1d5Smjnelson		file="$PF"
1867cdf0c1d5Smjnelson	else
1868cdf0c1d5Smjnelson		file="$PDIR/$PF"
1869cdf0c1d5Smjnelson	fi
1870b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
1871cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1872b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1873cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1874cdf0c1d5Smjnelson
1875cdf0c1d5Smjnelson	#
1876cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1877cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1878cdf0c1d5Smjnelson	#
1879cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1880cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1881cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1882cdf0c1d5Smjnelson			new_mode=755
1883cdf0c1d5Smjnelson		else
1884cdf0c1d5Smjnelson			new_mode=644
1885cdf0c1d5Smjnelson		fi
1886cdf0c1d5Smjnelson	fi
1887cdf0c1d5Smjnelson
1888cdf0c1d5Smjnelson	#
1889cdf0c1d5Smjnelson	# new version of the file.
1890cdf0c1d5Smjnelson	#
1891cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1892cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1893cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1894cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1895cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1896cdf0c1d5Smjnelson		else
1897cdf0c1d5Smjnelson			# should never happen
1898cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1899cdf0c1d5Smjnelson		fi
1900cdf0c1d5Smjnelson	fi
1901cdf0c1d5Smjnelson
1902cdf0c1d5Smjnelson	#
1903cdf0c1d5Smjnelson	# parent's version of the file
1904cdf0c1d5Smjnelson	#
1905cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1906cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1907cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1908cdf0c1d5Smjnelson	#
1909cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1910cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1911cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1912cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1913cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1914cdf0c1d5Smjnelson
191502d26c39SVladimir Kotal		if (( $? != 0 )); then
1916cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1917cdf0c1d5Smjnelson		else
1918cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1919cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1920cdf0c1d5Smjnelson			else
1921cdf0c1d5Smjnelson				# should never happen
1922cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1923cdf0c1d5Smjnelson			fi
1924cdf0c1d5Smjnelson		fi
1925cdf0c1d5Smjnelson	fi
1926cdf0c1d5Smjnelson}
1927cdf0c1d5Smjnelson
19288bcea973SRichard Lowefunction build_old_new_git
19298bcea973SRichard Lowe{
19308bcea973SRichard Lowe	typeset olddir="$1"
19318bcea973SRichard Lowe	typeset newdir="$2"
19328bcea973SRichard Lowe	typeset o_mode=
19338bcea973SRichard Lowe	typeset n_mode=
19348bcea973SRichard Lowe	typeset o_object=
19358bcea973SRichard Lowe	typeset n_object=
19368bcea973SRichard Lowe	typeset OWD=$PWD
19378bcea973SRichard Lowe	typeset file
19388bcea973SRichard Lowe	typeset type
19398bcea973SRichard Lowe
19408bcea973SRichard Lowe	cd $CWS
19418bcea973SRichard Lowe
19428bcea973SRichard Lowe	#
19438bcea973SRichard Lowe	# Get old file and its mode from the git object tree
19448bcea973SRichard Lowe	#
19458bcea973SRichard Lowe	if [[ "$PDIR" == "." ]]; then
19468bcea973SRichard Lowe		file="$PF"
19478bcea973SRichard Lowe	else
19488bcea973SRichard Lowe	       file="$PDIR/$PF"
19498bcea973SRichard Lowe	fi
19508bcea973SRichard Lowe
19518bcea973SRichard Lowe	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
19528bcea973SRichard Lowe		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
19538bcea973SRichard Lowe	else
19548bcea973SRichard Lowe                $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk
19558bcea973SRichard Lowe                $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null
19568bcea973SRichard Lowe
19578bcea973SRichard Lowe                if (( $? != 0 )); then
19588bcea973SRichard Lowe                        rm -f $olddir/$file
19598bcea973SRichard Lowe                elif [[ -n $o_mode ]]; then
19608bcea973SRichard Lowe                        # Strip the first 3 digits, to get a regular octal mode
19618bcea973SRichard Lowe                        o_mode=${o_mode/???/}
19628bcea973SRichard Lowe                        chmod $o_mode $olddir/$file
19638bcea973SRichard Lowe                else
19648bcea973SRichard Lowe                        # should never happen
19658bcea973SRichard Lowe                        print -u2 "ERROR: set mode of $olddir/$file"
19668bcea973SRichard Lowe                fi
19678bcea973SRichard Lowe	fi
19688bcea973SRichard Lowe
19698bcea973SRichard Lowe	#
19708bcea973SRichard Lowe	# new version of the file.
19718bcea973SRichard Lowe	#
19728bcea973SRichard Lowe	if [[ "$DIR" == "." ]]; then
19738bcea973SRichard Lowe		file="$F"
19748bcea973SRichard Lowe	else
19758bcea973SRichard Lowe		file="$DIR/$F"
19768bcea973SRichard Lowe	fi
19778bcea973SRichard Lowe	rm -rf $newdir/$file
19788bcea973SRichard Lowe
19798bcea973SRichard Lowe        if [[ -e $CWS/$DIR/$F ]]; then
19808bcea973SRichard Lowe            cp $CWS/$DIR/$F $newdir/$DIR/$F
19818bcea973SRichard Lowe            chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F
19828bcea973SRichard Lowe        fi
19838bcea973SRichard Lowe	cd $OWD
19848bcea973SRichard Lowe}
19858bcea973SRichard Lowe
1986cdf0c1d5Smjnelsonfunction build_old_new_subversion
1987cdf0c1d5Smjnelson{
1988cdf0c1d5Smjnelson	typeset olddir="$1"
1989cdf0c1d5Smjnelson	typeset newdir="$2"
1990cdf0c1d5Smjnelson
1991cdf0c1d5Smjnelson	# Snag new version of file.
1992cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1993cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
1994cdf0c1d5Smjnelson
1995cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
1996cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1997cdf0c1d5Smjnelson	else
1998cdf0c1d5Smjnelson		# Get the parent's version of the file.
1999cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2000cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2001cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2002cdf0c1d5Smjnelson		fi
2003cdf0c1d5Smjnelson	fi
2004cdf0c1d5Smjnelson}
2005cdf0c1d5Smjnelson
2006cdf0c1d5Smjnelsonfunction build_old_new_unknown
2007cdf0c1d5Smjnelson{
2008cdf0c1d5Smjnelson	typeset olddir="$1"
2009cdf0c1d5Smjnelson	typeset newdir="$2"
2010cdf0c1d5Smjnelson
2011cdf0c1d5Smjnelson	#
2012cdf0c1d5Smjnelson	# Snag new version of file.
2013cdf0c1d5Smjnelson	#
2014cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2015cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2016cdf0c1d5Smjnelson
2017cdf0c1d5Smjnelson	#
2018cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2019cdf0c1d5Smjnelson	#
2020cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2021cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2022cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2023cdf0c1d5Smjnelson	fi
2024cdf0c1d5Smjnelson}
2025cdf0c1d5Smjnelson
2026cdf0c1d5Smjnelsonfunction build_old_new
2027cdf0c1d5Smjnelson{
2028cdf0c1d5Smjnelson	typeset WDIR=$1
2029cdf0c1d5Smjnelson	typeset PWS=$2
2030cdf0c1d5Smjnelson	typeset PDIR=$3
2031cdf0c1d5Smjnelson	typeset PF=$4
2032cdf0c1d5Smjnelson	typeset CWS=$5
2033cdf0c1d5Smjnelson	typeset DIR=$6
2034cdf0c1d5Smjnelson	typeset F=$7
2035cdf0c1d5Smjnelson
2036cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2037cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2038cdf0c1d5Smjnelson
2039cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2040cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2041cdf0c1d5Smjnelson
2042d7b56f41SBart Coddens	if [[ $SCM_MODE == "mercurial" ]]; then
2043cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
20448bcea973SRichard Lowe	elif [[ $SCM_MODE == "git" ]]; then
20458bcea973SRichard Lowe		build_old_new_git "$olddir" "$newdir"
2046cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2047cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2048cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2049cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2050cdf0c1d5Smjnelson	fi
2051cdf0c1d5Smjnelson
2052cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2053cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2054cdf0c1d5Smjnelson		return 1
2055cdf0c1d5Smjnelson	fi
2056cdf0c1d5Smjnelson	return 0
2057cdf0c1d5Smjnelson}
2058cdf0c1d5Smjnelson
2059cdf0c1d5Smjnelson
2060daaffb31Sdp#
2061daaffb31Sdp# Usage message.
2062daaffb31Sdp#
2063daaffb31Sdpfunction usage
2064daaffb31Sdp{
2065daaffb31Sdp	print 'Usage:\twebrev [common-options]
2066daaffb31Sdp	webrev [common-options] ( <file> | - )
2067daaffb31Sdp	webrev [common-options] -w <wx file>
2068daaffb31Sdp
2069daaffb31SdpOptions:
20700fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2071ba44d8a2SVladimir Kotal	-D: delete remote webrev
2072daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
20730fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2074ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2075ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2076daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2077daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
207802d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
207902d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2080daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2081daaffb31Sdp
2082daaffb31SdpEnvironment:
2083daaffb31Sdp	WDIR: Control the output directory.
2084ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2085daaffb31Sdp
2086daaffb31SdpSCM Environment:
2087cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2088cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2089daaffb31Sdp'
2090daaffb31Sdp
2091daaffb31Sdp	exit 2
2092daaffb31Sdp}
2093daaffb31Sdp
2094daaffb31Sdp#
2095daaffb31Sdp#
2096daaffb31Sdp# Main program starts here
2097daaffb31Sdp#
2098daaffb31Sdp#
2099daaffb31Sdp
2100daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2101daaffb31Sdp
2102daaffb31Sdpset +o noclobber
2103daaffb31Sdp
21048bcea973SRichard LowePATH=$(/bin/dirname "$(whence $0)"):$PATH
2105cdf0c1d5Smjnelson
210614983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
210714983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2108cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
21098bcea973SRichard Lowe[[ -z $GIT ]] && GIT=`look_for_prog git`
2110cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
211114983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
211214983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
211314983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
211402d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2115cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2116cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2117cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2118cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
211902d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2120b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
212102d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2122e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort`
212302d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
212402d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2125ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2126cdf0c1d5Smjnelson
2127ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2128ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2129ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
213014983201Sdp
213114983201Sdpif [[ ! -x $PERL ]]; then
213214983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
213314983201Sdp	exit 1
2134daaffb31Sdpfi
213514983201Sdp
2136cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2137cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2138cdf0c1d5Smjnelson	exit 1
2139cdf0c1d5Smjnelsonfi
2140cdf0c1d5Smjnelson
214114983201Sdp#
214214983201Sdp# These aren't fatal, but we want to note them to the user.
214314983201Sdp# We don't warn on the absence of 'wx' until later when we've
214414983201Sdp# determined that we actually need to try to invoke it.
214514983201Sdp#
214614983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
214714983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
214814983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2149daaffb31Sdp
2150daaffb31Sdp# Declare global total counters.
2151daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2152daaffb31Sdp
2153ba44d8a2SVladimir Kotal# default remote host for upload/delete
2154ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2155b0088928SVladimir Kotal# prefixes for upload targets
2156b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2157b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2158ba44d8a2SVladimir Kotal
21590fd2682eSMark J. NelsonCflag=
2160ba44d8a2SVladimir KotalDflag=
216114983201Sdpflist_mode=
216214983201Sdpflist_file=
2163daaffb31Sdpiflag=
21640fd2682eSMark J. NelsonIflag=
216502d26c39SVladimir Kotallflag=
216602d26c39SVladimir KotalNflag=
216702d26c39SVladimir Kotalnflag=
216802d26c39SVladimir KotalOflag=
2169daaffb31Sdpoflag=
2170daaffb31Sdppflag=
217102d26c39SVladimir Kotaltflag=
217202d26c39SVladimir Kotaluflag=
217302d26c39SVladimir KotalUflag=
2174daaffb31Sdpwflag=
217502d26c39SVladimir Kotalremote_target=
2176ba44d8a2SVladimir Kotal
2177ba44d8a2SVladimir Kotal#
2178ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2179ba44d8a2SVladimir Kotal#	with usr/src/tools/onbld/hgext/cdm.py
2180ba44d8a2SVladimir Kotal#
218125cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
2182daaffb31Sdpdo
2183daaffb31Sdp	case $opt in
21840fd2682eSMark J. Nelson	C)	Cflag=1
21850fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
21860fd2682eSMark J. Nelson
2187ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2188ba44d8a2SVladimir Kotal
2189daaffb31Sdp	i)	iflag=1
2190daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2191daaffb31Sdp
21920fd2682eSMark J. Nelson	I)	Iflag=1
21930fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
21940fd2682eSMark J. Nelson
219502d26c39SVladimir Kotal	N)	Nflag=1;;
219602d26c39SVladimir Kotal
219702d26c39SVladimir Kotal	n)	nflag=1;;
2198daaffb31Sdp
2199daaffb31Sdp	O)	Oflag=1;;
2200daaffb31Sdp
220102d26c39SVladimir Kotal	o)	oflag=1
22029d3952abSVladimir Kotal		# Strip the trailing slash to correctly form remote target.
22039d3952abSVladimir Kotal		WDIR=${OPTARG%/};;
220402d26c39SVladimir Kotal
220502d26c39SVladimir Kotal	p)	pflag=1
220602d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
220702d26c39SVladimir Kotal
220802d26c39SVladimir Kotal	t)	tflag=1
220902d26c39SVladimir Kotal		remote_target=$OPTARG;;
221002d26c39SVladimir Kotal
221102d26c39SVladimir Kotal	U)	Uflag=1;;
221202d26c39SVladimir Kotal
221302d26c39SVladimir Kotal	w)	wflag=1;;
22143df69ef3SDarren Moffat
2215daaffb31Sdp	?)	usage;;
2216daaffb31Sdp	esac
2217daaffb31Sdpdone
2218daaffb31Sdp
2219daaffb31SdpFLIST=/tmp/$$.flist
2220daaffb31Sdp
2221daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2222daaffb31Sdp	usage
2223daaffb31Sdpfi
2224daaffb31Sdp
222502d26c39SVladimir Kotal# more sanity checking
222602d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2227ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2228ba44d8a2SVladimir Kotal	    "without -U"
222902d26c39SVladimir Kotal	exit 1
223002d26c39SVladimir Kotalfi
223102d26c39SVladimir Kotal
2232ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2233ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
223402d26c39SVladimir Kotal	exit 1
223502d26c39SVladimir Kotalfi
223602d26c39SVladimir Kotal
2237daaffb31Sdp#
22382d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume
22392d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name
22402d9224a3SMark J. Nelson# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
22412d9224a3SMark J. Nelson# logic.
22422d9224a3SMark J. Nelson#
22432d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1
2244d7b56f41SBart Coddensif [[ $SCM_MODE == "mercurial" ]]; then
22452d9224a3SMark J. Nelson	#
22462d9224a3SMark J. Nelson	# Mercurial priorities:
22472d9224a3SMark J. Nelson	# 1. hg root from CODEMGR_WS environment variable
224878add226Sjmcp	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
224978add226Sjmcp	#    usr/closed when we run webrev
22502d9224a3SMark J. Nelson	# 2. hg root from directory of invocation
22512d9224a3SMark J. Nelson	#
225278add226Sjmcp	if [[ ${PWD} =~ "usr/closed" ]]; then
225378add226Sjmcp		testparent=${CODEMGR_WS}/usr/closed
225478add226Sjmcp		# If we're in OpenSolaris mode, we enforce a minor policy:
225578add226Sjmcp		# help to make sure the reviewer doesn't accidentally publish
225678add226Sjmcp		# source which is under usr/closed
225778add226Sjmcp		if [[ -n "$Oflag" ]]; then
225878add226Sjmcp			print -u2 "OpenSolaris output not permitted with" \
225978add226Sjmcp			    "usr/closed changes"
226078add226Sjmcp			exit 1
226178add226Sjmcp		fi
226278add226Sjmcp	else
226378add226Sjmcp	        testparent=${CODEMGR_WS}
226478add226Sjmcp	fi
226578add226Sjmcp	[[ -z $codemgr_ws && -n $testparent ]] && \
226678add226Sjmcp	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
22672d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
22682d9224a3SMark J. Nelson	CWS=$codemgr_ws
22698bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
22708bcea973SRichard Lowe	#
22718bcea973SRichard Lowe	# Git priorities:
22728bcea973SRichard Lowe	# 1. git rev-parse --git-dir from CODEMGR_WS environment variable
22738bcea973SRichard Lowe	# 2. git rev-parse --git-dir from directory of invocation
22748bcea973SRichard Lowe	#
22758bcea973SRichard Lowe	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
22768bcea973SRichard Lowe	    codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
22778bcea973SRichard Lowe                2>/dev/null)
22788bcea973SRichard Lowe	[[ -z $codemgr_ws ]] && \
22798bcea973SRichard Lowe	    codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
22808bcea973SRichard Lowe
22818bcea973SRichard Lowe	if [[ "$codemgr_ws" == ".git" ]]; then
22828bcea973SRichard Lowe		codemgr_ws="${PWD}/${codemgr_ws}"
22838bcea973SRichard Lowe	fi
22848bcea973SRichard Lowe
22858bcea973SRichard Lowe	codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
22868bcea973SRichard Lowe	CWS="$codemgr_ws"
22872d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then
22882d9224a3SMark J. Nelson	#
22892d9224a3SMark J. Nelson	# Subversion priorities:
22902d9224a3SMark J. Nelson	# 1. CODEMGR_WS from environment
22912d9224a3SMark J. Nelson	# 2. Relative path from current directory to SVN repository root
22922d9224a3SMark J. Nelson	#
22932d9224a3SMark J. Nelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
22942d9224a3SMark J. Nelson		CWS=$CODEMGR_WS
22952d9224a3SMark J. Nelson	else
22962d9224a3SMark J. Nelson		svn info | while read line; do
22972d9224a3SMark J. Nelson			if [[ $line == "URL: "* ]]; then
22982d9224a3SMark J. Nelson				url=${line#URL: }
22992d9224a3SMark J. Nelson			elif [[ $line == "Repository Root: "* ]]; then
23002d9224a3SMark J. Nelson				repo=${line#Repository Root: }
23012d9224a3SMark J. Nelson			fi
23022d9224a3SMark J. Nelson		done
23032d9224a3SMark J. Nelson
23042d9224a3SMark J. Nelson		rel=${url#$repo}
23052d9224a3SMark J. Nelson		CWS=${PWD%$rel}
23062d9224a3SMark J. Nelson	fi
23072d9224a3SMark J. Nelsonfi
23082d9224a3SMark J. Nelson
23092d9224a3SMark J. Nelson#
23102d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting
23112d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set.
23122d9224a3SMark J. Nelson#
23132d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then
23142d9224a3SMark J. Nelson	CWS=${CODEMGR_WS:-.}
23152d9224a3SMark J. Nelsonfi
23162d9224a3SMark J. Nelson
23172d9224a3SMark J. Nelson#
23180fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
23190fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
23200fd2682eSMark J. Nelson# ton of logic we can skip.
23210fd2682eSMark J. Nelson#
23220fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
23230fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
23240fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
23250fd2682eSMark J. Nelson#
23260fd2682eSMark J. Nelsonfor do_everything in 1; do
23270fd2682eSMark J. Nelson
23280fd2682eSMark J. Nelson# DO_EVERYTHING: break point
23290fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
23300fd2682eSMark J. Nelson	break
23310fd2682eSMark J. Nelsonfi
23320fd2682eSMark J. Nelson
23330fd2682eSMark J. Nelson#
2334daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2335daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2336daaffb31Sdp#
2337daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
23388bcea973SRichard Lowe	parent_webrev=$(readlink -f "$codemgr_parent")
23398bcea973SRichard Lowe	codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new")
2340daaffb31Sdpfi
2341daaffb31Sdp
2342daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2343daaffb31Sdp	shift $(($OPTIND - 1))
2344daaffb31Sdp
2345daaffb31Sdp	if [[ $1 == "-" ]]; then
2346daaffb31Sdp		cat > $FLIST
234714983201Sdp		flist_mode="stdin"
234814983201Sdp		flist_done=1
234914983201Sdp		shift
2350daaffb31Sdp	elif [[ -n $1 ]]; then
235114983201Sdp		if [[ ! -r $1 ]]; then
2352daaffb31Sdp			print -u2 "$1: no such file or not readable"
2353daaffb31Sdp			usage
2354daaffb31Sdp		fi
2355daaffb31Sdp		cat $1 > $FLIST
235614983201Sdp		flist_mode="file"
235714983201Sdp		flist_file=$1
235814983201Sdp		flist_done=1
235914983201Sdp		shift
2360daaffb31Sdp	else
236114983201Sdp		flist_mode="auto"
2362daaffb31Sdp	fi
2363daaffb31Sdpfi
2364daaffb31Sdp
2365daaffb31Sdp#
2366daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2367daaffb31Sdp# is in use.
2368daaffb31Sdp#
2369cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2370d7b56f41SBart Coddensmercurial|git|subversion)
2371cdf0c1d5Smjnelson	;;
2372cdf0c1d5Smjnelsonunknown)
2373cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2374cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2375cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
23767c478bd9Sstevel@tonic-gate		exit 1
23777c478bd9Sstevel@tonic-gate	fi
2378cdf0c1d5Smjnelson	;;
2379cdf0c1d5Smjnelson*)
2380cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2381cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2382cdf0c1d5Smjnelson		exit 1
2383cdf0c1d5Smjnelson	fi
2384cdf0c1d5Smjnelson	;;
2385cdf0c1d5Smjnelsonesac
23867c478bd9Sstevel@tonic-gate
2387daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2388daaffb31Sdp
2389d7b56f41SBart Coddensif [[ -n $wflag ]]; then
2390daaffb31Sdp	#
2391daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2392daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2393daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2394daaffb31Sdp	# in building the index.html file.
2395daaffb31Sdp	#
2396daaffb31Sdp	shift $(($OPTIND - 1))
2397daaffb31Sdp	wxfile=$1
2398daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2399daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2400daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2401daaffb31Sdp		fi
2402daaffb31Sdp	fi
2403daaffb31Sdp
2404daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2405daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2406daaffb31Sdp
2407cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2408cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2409cdf0c1d5Smjnelson		usage
2410cdf0c1d5Smjnelson	fi
2411cdf0c1d5Smjnelson
2412daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2413daaffb31Sdp	flist_from_wx $wxfile
2414daaffb31Sdp	flist_done=1
2415daaffb31Sdp	if [[ -n "$*" ]]; then
2416daaffb31Sdp		shift
2417daaffb31Sdp	fi
241814983201Sdpelif [[ $flist_mode == "stdin" ]]; then
241914983201Sdp	print -u2 " File list from: standard input"
242014983201Sdpelif [[ $flist_mode == "file" ]]; then
242114983201Sdp	print -u2 " File list from: $flist_file"
2422daaffb31Sdpfi
2423daaffb31Sdp
2424daaffb31Sdpif [[ $# -gt 0 ]]; then
242514983201Sdp	print -u2 "WARNING: unused arguments: $*"
2426daaffb31Sdpfi
2427daaffb31Sdp
24282d9224a3SMark J. Nelson#
24292d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS
24302d9224a3SMark J. Nelson# and CODEMGR_WS as needed.  Here, we set the parent workspace.
24312d9224a3SMark J. Nelson#
2432d7b56f41SBart Coddensif [[ $SCM_MODE == "mercurial" ]]; then
2433cdf0c1d5Smjnelson	#
2434cdf0c1d5Smjnelson	# Parent can either be specified with -p
2435cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2436cdf0c1d5Smjnelson	# or taken from hg's default path.
2437cdf0c1d5Smjnelson	#
2438cdf0c1d5Smjnelson
2439cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2440cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2441cdf0c1d5Smjnelson	fi
2442cdf0c1d5Smjnelson
2443cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2444cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2445cdf0c1d5Smjnelson	fi
2446cdf0c1d5Smjnelson
2447cdf0c1d5Smjnelson	PWS=$codemgr_parent
2448cdf0c1d5Smjnelson
2449cdf0c1d5Smjnelson	#
2450cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2451cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2452cdf0c1d5Smjnelson	#
2453cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2454cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2455cdf0c1d5Smjnelson	else
2456cdf0c1d5Smjnelson		real_parent=$PWS
2457cdf0c1d5Smjnelson	fi
2458cdf0c1d5Smjnelson
2459cdf0c1d5Smjnelson	#
2460cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2461cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2462cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2463cdf0c1d5Smjnelson	# files mentioned in the flist.
2464cdf0c1d5Smjnelson	#
2465cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2466cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2467cdf0c1d5Smjnelson		flist_done=1
2468cdf0c1d5Smjnelson	fi
2469cdf0c1d5Smjnelson
2470cdf0c1d5Smjnelson	#
2471cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2472cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2473cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2474cdf0c1d5Smjnelson	# in the user-specified flist.
2475cdf0c1d5Smjnelson	#
2476cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2477cdf0c1d5Smjnelson		env_from_flist
2478cdf0c1d5Smjnelson	fi
2479cdf0c1d5Smjnelson
2480cdf0c1d5Smjnelson	#
2481cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2482cdf0c1d5Smjnelson	#
2483cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2484cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2485cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2486cdf0c1d5Smjnelson		print " Done."
2487cdf0c1d5Smjnelson	fi
2488cdf0c1d5Smjnelson
2489cdf0c1d5Smjnelson	#
2490cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2491cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2492cdf0c1d5Smjnelson	# if we don't have one.
2493cdf0c1d5Smjnelson	#
2494cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2495b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2496cdf0c1d5Smjnelson	fi
2497cdf0c1d5Smjnelson
2498cdf0c1d5Smjnelson	#
2499cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2500cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2501cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2502cdf0c1d5Smjnelson	#
2503cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2504cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2505b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2506cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2507cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2508cdf0c1d5Smjnelson		exit 1
2509cdf0c1d5Smjnelson	fi
25108bcea973SRichard Lowe
25118bcea973SRichard Lowe	pnode=$(trim_digest $HG_PARENT)
25128bcea973SRichard Lowe	PRETTY_PWS="${PWS} (at ${pnode})"
25138bcea973SRichard Lowe	cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
25148bcea973SRichard Lowe	    2>/dev/null)
25158bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"}
25168bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
25178bcea973SRichard Lowe	#
25188bcea973SRichard Lowe	# Parent can either be specified with -p, or specified with
25198bcea973SRichard Lowe	# CODEMGR_PARENT in the environment.
25208bcea973SRichard Lowe	#
25218bcea973SRichard Lowe
25228bcea973SRichard Lowe	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
25238bcea973SRichard Lowe		codemgr_parent=$CODEMGR_PARENT
25248bcea973SRichard Lowe	fi
25258bcea973SRichard Lowe
25268bcea973SRichard Lowe	# Try to figure out the parent based on the branch the current
25278bcea973SRichard Lowe	# branch is tracking, if we fail, use origin/master
25288bcea973SRichard Lowe	this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }')
25298bcea973SRichard Lowe	par_branch="origin/master"
25308bcea973SRichard Lowe
25318bcea973SRichard Lowe        # If we're not on a branch there's nothing we can do
25328bcea973SRichard Lowe        if [[ $this_branch != "(no branch)" ]]; then
25338bcea973SRichard Lowe                $GIT for-each-ref                                                 \
25348bcea973SRichard Lowe                    --format='%(refname:short) %(upstream:short)' refs/heads/ |   \
25358bcea973SRichard Lowe                    while read local remote; do                                   \
25368bcea973SRichard Lowe                	[[ "$local" == "$this_branch" ]] && par_branch="$remote"; \
25378bcea973SRichard Lowe                    done
25388bcea973SRichard Lowe	fi
25398bcea973SRichard Lowe
25408bcea973SRichard Lowe	if [[ -z $codemgr_parent ]]; then
25418bcea973SRichard Lowe		codemgr_parent=$par_branch
25428bcea973SRichard Lowe	fi
25438bcea973SRichard Lowe	PWS=$codemgr_parent
25448bcea973SRichard Lowe
25458bcea973SRichard Lowe	#
25468bcea973SRichard Lowe	# If the parent is a webrev, we want to do some things against
25478bcea973SRichard Lowe	# the natural workspace parent (file list, comments, etc)
25488bcea973SRichard Lowe	#
25498bcea973SRichard Lowe	if [[ -n $parent_webrev ]]; then
25508bcea973SRichard Lowe		real_parent=$par_branch
25518bcea973SRichard Lowe	else
25528bcea973SRichard Lowe		real_parent=$PWS
25538bcea973SRichard Lowe	fi
25548bcea973SRichard Lowe
25558bcea973SRichard Lowe	if [[ -z $flist_done ]]; then
25568bcea973SRichard Lowe		flist_from_git "$CWS" "$real_parent"
25578bcea973SRichard Lowe		flist_done=1
25588bcea973SRichard Lowe	fi
25598bcea973SRichard Lowe
25608bcea973SRichard Lowe	#
25618bcea973SRichard Lowe	# If we have a file list now, pull out any variables set
25628bcea973SRichard Lowe	# therein.
25638bcea973SRichard Lowe	#
25648bcea973SRichard Lowe	if [[ -n $flist_done ]]; then
25658bcea973SRichard Lowe		env_from_flist
25668bcea973SRichard Lowe	fi
25678bcea973SRichard Lowe
25688bcea973SRichard Lowe	#
25698bcea973SRichard Lowe	# If we don't have a wx-format file list, build one we can pull change
25708bcea973SRichard Lowe	# comments from.
25718bcea973SRichard Lowe	#
25728bcea973SRichard Lowe	if [[ -z $wxfile ]]; then
25738bcea973SRichard Lowe		print "  Comments from: git...\c"
25748bcea973SRichard Lowe		git_wxfile "$CWS" "$real_parent"
25758bcea973SRichard Lowe		print " Done."
25768bcea973SRichard Lowe	fi
25778bcea973SRichard Lowe
25788bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
25798bcea973SRichard Lowe		GIT_PARENT=$($GIT merge-base "$real_parent" HEAD)
25808bcea973SRichard Lowe	fi
25818bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
25828bcea973SRichard Lowe		print -u2 "Error: Cannot discover parent revision"
25838bcea973SRichard Lowe		exit 1
25848bcea973SRichard Lowe	fi
25858bcea973SRichard Lowe
25868bcea973SRichard Lowe	pnode=$(trim_digest $GIT_PARENT)
25878bcea973SRichard Lowe
25888bcea973SRichard Lowe	if [[ $real_parent == */* ]]; then
25898bcea973SRichard Lowe		origin=$(echo $real_parent | cut -d/ -f1)
25908bcea973SRichard Lowe		origin=$($GIT remote -v | \
25918bcea973SRichard Lowe		    $AWK '$1 == "'$origin'" { print $2; exit }')
25928bcea973SRichard Lowe		PRETTY_PWS="${PWS} (${origin} at ${pnode})"
25938bcea973SRichard Lowe	else
25948bcea973SRichard Lowe		PRETTY_PWS="${PWS} (at ${pnode})"
25958bcea973SRichard Lowe	fi
25968bcea973SRichard Lowe
25978bcea973SRichard Lowe	cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \
25988bcea973SRichard Lowe	    2>/dev/null)
25998bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"
2600cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2601cdf0c1d5Smjnelson
2602cdf0c1d5Smjnelson	#
2603cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2604cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2605cdf0c1d5Smjnelson	#
2606cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2607cdf0c1d5Smjnelson
2608cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2609cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2610cdf0c1d5Smjnelson	fi
2611cdf0c1d5Smjnelsonelse
2612cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2613cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2614cdf0c1d5Smjnelson    else
2615cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2616cdf0c1d5Smjnelson    fi
2617cdf0c1d5Smjnelson
2618cdf0c1d5Smjnelson    env_from_flist
2619cdf0c1d5Smjnelson
2620cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2621cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2622cdf0c1d5Smjnelson	exit 1
2623cdf0c1d5Smjnelson    fi
2624cdf0c1d5Smjnelson
2625cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2626cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2627cdf0c1d5Smjnelson	exit 1
2628cdf0c1d5Smjnelson    fi
2629cdf0c1d5Smjnelson
2630cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2631cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2632daaffb31Sdpfi
2633daaffb31Sdp
2634daaffb31Sdp#
2635daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2636daaffb31Sdp# webrev-info file in the workspace directory.
2637daaffb31Sdp#
2638daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2639daaffb31Sdp	iflag=1
2640daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2641daaffb31Sdpfi
2642daaffb31Sdp
2643daaffb31Sdpif [[ -n $iflag ]]; then
2644daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2645daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2646daaffb31Sdp		    "not readable."
2647daaffb31Sdp		exit 1
2648daaffb31Sdp	else
2649daaffb31Sdp		#
2650daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2651daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2652daaffb31Sdp		#
2653daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2654daaffb31Sdp	fi
2655daaffb31Sdpfi
2656daaffb31Sdp
26570fd2682eSMark J. Nelson# DO_EVERYTHING: break point
26580fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
26590fd2682eSMark J. Nelson	break
26600fd2682eSMark J. Nelsonfi
26610fd2682eSMark J. Nelson
26620fd2682eSMark J. Nelsontypeset -A itsinfo
26630fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
26640fd2682eSMark J. Nelsonvalid_prefixes=
26650fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
26668bcea973SRichard Lowe	DEFREGFILE="$(/bin/dirname "$(whence $0)")/../etc/its.reg"
26670fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
26680fd2682eSMark J. Nelson		REGFILE=$ITSREG
26690fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
26700fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
26710fd2682eSMark J. Nelson	else
26720fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
26730fd2682eSMark J. Nelson	fi
26740fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
26750fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
26760fd2682eSMark J. Nelson		exit 1
26770fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
26780fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
26790fd2682eSMark J. Nelson	fi
26800fd2682eSMark J. Nelson
26810fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
26820fd2682eSMark J. Nelson
26830fd2682eSMark J. Nelson		name=${LINE%%=*}
26840fd2682eSMark J. Nelson		value="${LINE#*=}"
26850fd2682eSMark J. Nelson
26860fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
26870fd2682eSMark J. Nelson			p=${value}
26880fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
26890fd2682eSMark J. Nelson		else
26900fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
26910fd2682eSMark J. Nelson		fi
26920fd2682eSMark J. Nelson	done
26930fd2682eSMark J. Nelson
26940fd2682eSMark J. Nelson
26958bcea973SRichard Lowe	DEFCONFFILE="$(/bin/dirname "$(whence $0)")/../etc/its.conf"
26960fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
26970fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
26980fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
26990fd2682eSMark J. Nelson	fi
27000fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
27010fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
27020fd2682eSMark J. Nelson	fi
27030fd2682eSMark J. Nelson	its_domain=
27040fd2682eSMark J. Nelson	its_priority=
27050fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
27060fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
27070fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
27080fd2682eSMark J. Nelson			exit 1
27090fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
27100fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
27110fd2682eSMark J. Nelson		fi
27120fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
27130fd2682eSMark J. Nelson		    eval "${LINE}"
27140fd2682eSMark J. Nelson		done
27150fd2682eSMark J. Nelson	done
27160fd2682eSMark J. Nelson
27170fd2682eSMark J. Nelson	#
27180fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
27190fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
27200fd2682eSMark J. Nelson	#
27210fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
27220fd2682eSMark J. Nelson	#
27230fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
27240fd2682eSMark J. Nelson		#
27250fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
27260fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
27270fd2682eSMark J. Nelson		#
27280fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
27290fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
27300fd2682eSMark J. Nelson		else
27310fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
27320fd2682eSMark J. Nelson		fi
27330fd2682eSMark J. Nelson
27340fd2682eSMark J. Nelson		#
27350fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
27360fd2682eSMark J. Nelson		# to this information tracking system should resolve through
27370fd2682eSMark J. Nelson		# the same URL.
27380fd2682eSMark J. Nelson		#
27390fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
27400fd2682eSMark J. Nelson		#
27410fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
27420fd2682eSMark J. Nelson		# INTERNAL_URL.
27430fd2682eSMark J. Nelson		#
27440fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
27450fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
27460fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
27470fd2682eSMark J. Nelson				break
27480fd2682eSMark J. Nelson			fi
27490fd2682eSMark J. Nelson		done
27500fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
27510fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
27520fd2682eSMark J. Nelson		fi
27530fd2682eSMark J. Nelson
27540fd2682eSMark J. Nelson		#
27550fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
27560fd2682eSMark J. Nelson		#
27570fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
27580fd2682eSMark J. Nelson
27592f54b716SRichard Lowe		# The character class below contains a literal tab
27602f54b716SRichard Lowe		print "/^${p}[: 	]/ {
27610fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27620fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
27630fd2682eSMark J. Nelson			}" >> ${its_sed_script}
27640fd2682eSMark J. Nelson	done
27650fd2682eSMark J. Nelson
27660fd2682eSMark J. Nelson	#
27670fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
27680fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
27690fd2682eSMark J. Nelson	#
27700fd2682eSMark J. Nelson	for p in ${its_priority}; do
27710fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
27722f54b716SRichard Lowe				s;^${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27730fd2682eSMark J. Nelson			}" >> ${its_sed_script}
27740fd2682eSMark J. Nelson	done
27750fd2682eSMark J. Nelsonfi
27760fd2682eSMark J. Nelson
27770fd2682eSMark J. Nelson#
27780fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
27790fd2682eSMark J. Nelson# and explanation of this terminator.
27800fd2682eSMark J. Nelson#
27810fd2682eSMark J. Nelsondone
27820fd2682eSMark J. Nelson
2783daaffb31Sdp#
2784daaffb31Sdp# Output directory.
2785daaffb31Sdp#
2786daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2787daaffb31Sdp
2788daaffb31Sdp#
278902d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
279002d26c39SVladimir Kotal# in the future this could potentially be an option.
2791daaffb31Sdp#
279202d26c39SVladimir Kotalif [[ -n $oflag ]]; then
279302d26c39SVladimir Kotal	WNAME=${WDIR##*/}
279402d26c39SVladimir Kotalelse
2795daaffb31Sdp	WNAME=${CWS##*/}
279602d26c39SVladimir Kotalfi
279702d26c39SVladimir Kotal
2798ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2799ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2800b0088928SVladimir Kotal	#
2801ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2802ba44d8a2SVladimir Kotal	# the default values.
2803b0088928SVladimir Kotal	#
2804ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2805ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2806ba44d8a2SVladimir Kotal	else
2807b0088928SVladimir Kotal		#
2808b0088928SVladimir Kotal		# Check upload target prefix first.
2809b0088928SVladimir Kotal		#
2810b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
2811b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
2812b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
2813b0088928SVladimir Kotal			    "($remote_target)"
2814b0088928SVladimir Kotal			exit 1
2815b0088928SVladimir Kotal		fi
2816b0088928SVladimir Kotal		#
2817ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2818ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2819ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2820ba44d8a2SVladimir Kotal		# local webrev directory name.
2821b0088928SVladimir Kotal		#
2822b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
2823b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
2824ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2825b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
2826ba44d8a2SVladimir Kotal			fi
2827b0088928SVladimir Kotal		else
2828b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
2829b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
2830b0088928SVladimir Kotal					"($remote_target)"
2831b0088928SVladimir Kotal				exit 1
2832b0088928SVladimir Kotal			else
2833b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
2834ba44d8a2SVladimir Kotal			fi
2835ba44d8a2SVladimir Kotal		fi
2836ba44d8a2SVladimir Kotal	fi
2837ba44d8a2SVladimir Kotal
2838b0088928SVladimir Kotal	#
2839b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
2840b0088928SVladimir Kotal	# specification separately.
2841b0088928SVladimir Kotal	#
2842b0088928SVladimir Kotal	remote_target=${remote_target%/}
2843b0088928SVladimir Kotalfi
2844b0088928SVladimir Kotal
2845b0088928SVladimir Kotal#
2846ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2847b0088928SVladimir Kotal#
2848ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2849b0088928SVladimir Kotal	delete_webrev 1 1
2850ba44d8a2SVladimir Kotal	exit $?
2851ba44d8a2SVladimir Kotalfi
2852ba44d8a2SVladimir Kotal
2853b0088928SVladimir Kotal#
2854ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2855b0088928SVladimir Kotal#
2856ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2857ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2858b0088928SVladimir Kotal		delete_webrev 1 1
2859ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2860ba44d8a2SVladimir Kotal	fi
2861ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
286202d26c39SVladimir Kotal		upload_webrev
286302d26c39SVladimir Kotal		exit $?
286402d26c39SVladimir Kotal	fi
2865ba44d8a2SVladimir Kotalfi
2866daaffb31Sdp
2867e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
28687c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
28697c478bd9Sstevel@tonic-gatefi
2870daaffb31Sdp
2871daaffb31Sdpif [[ ! -d $WDIR ]]; then
2872daaffb31Sdp	mkdir -p $WDIR
2873ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
28747c478bd9Sstevel@tonic-gatefi
28757c478bd9Sstevel@tonic-gate
2876daaffb31Sdp#
2877daaffb31Sdp# Summarize what we're going to do.
2878daaffb31Sdp#
28798bcea973SRichard Loweprint "      Workspace: ${PRETTY_CWS:-$CWS}"
2880daaffb31Sdpif [[ -n $parent_webrev ]]; then
2881daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2882daaffb31Sdpelse
28838bcea973SRichard Lowe	print "Compare against: ${PRETTY_PWS:-$PWS}"
2884cdf0c1d5Smjnelsonfi
2885daaffb31Sdp
2886daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2887daaffb31Sdpprint "      Output to: $WDIR"
2888daaffb31Sdp
2889daaffb31Sdp#
28907c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2891daaffb31Sdp#
2892daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
28937c478bd9Sstevel@tonic-gate
2894daaffb31Sdprm -f $WDIR/$WNAME.patch
2895daaffb31Sdprm -f $WDIR/$WNAME.ps
2896daaffb31Sdprm -f $WDIR/$WNAME.pdf
28977c478bd9Sstevel@tonic-gate
2898daaffb31Sdptouch $WDIR/$WNAME.patch
28997c478bd9Sstevel@tonic-gate
2900daaffb31Sdpprint "   Output Files:"
2901daaffb31Sdp
2902daaffb31Sdp#
2903daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2904daaffb31Sdp#
2905b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2906daaffb31SdpFLIST=/tmp/$$.flist.clean
2907daaffb31Sdp
2908daaffb31Sdp#
2909cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2910cdf0c1d5Smjnelson#
2911cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2912cdf0c1d5Smjnelson	#
2913cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2914cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2915cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2916cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2917cdf0c1d5Smjnelson	#    keep only the old name.
2918cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2919cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2920cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2921cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2922cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2923e6ccc173SEdward Pilatowicz	# 4) Eliminate any duplicate entries.  (This can occur if a
2924e6ccc173SEdward Pilatowicz	#    file has been used as the source of an hg cp and it's
2925e6ccc173SEdward Pilatowicz	#    also been modified in the same changeset.)
2926cdf0c1d5Smjnelson	#
2927cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2928b0088928SVladimir Kotal	$SED '
2929cdf0c1d5Smjnelson		s#^[^ ]* ##
2930cdf0c1d5Smjnelson		s#/#\\\/#g
2931cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2932e6ccc173SEdward Pilatowicz	' < $FLIST | $SORT -u > $SEDFILE
2933cdf0c1d5Smjnelson
2934cdf0c1d5Smjnelson	#
2935cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2936cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2937cdf0c1d5Smjnelson	#
2938cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2939cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2940b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2941cdf0c1d5Smjnelsonfi
2942cdf0c1d5Smjnelson
2943cdf0c1d5Smjnelson#
2944daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2945daaffb31Sdp#
2946daaffb31Sdpcat $FLIST | while read LINE
29477c478bd9Sstevel@tonic-gatedo
29487c478bd9Sstevel@tonic-gate	set - $LINE
29497c478bd9Sstevel@tonic-gate	P=$1
29507c478bd9Sstevel@tonic-gate
2951daaffb31Sdp	#
2952daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2953daaffb31Sdp	# file that has been modified or created in the child.  A file
2954daaffb31Sdp	# that is renamed in the child workspace has two names on the
2955daaffb31Sdp	# line: new name followed by the old name.
2956daaffb31Sdp	#
2957daaffb31Sdp	oldname=""
2958daaffb31Sdp	oldpath=""
2959daaffb31Sdp	rename=
2960daaffb31Sdp	if [[ $# -eq 2 ]]; then
29617c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2962e6ccc173SEdward Pilatowicz		if [[ -f $PP ]]; then
2963e6ccc173SEdward Pilatowicz			oldname=" (copied from $PP)"
2964e6ccc173SEdward Pilatowicz		else
2965e6ccc173SEdward Pilatowicz			oldname=" (renamed from $PP)"
2966e6ccc173SEdward Pilatowicz		fi
2967daaffb31Sdp		oldpath="$PP"
2968daaffb31Sdp		rename=1
29697c478bd9Sstevel@tonic-gate		PDIR=${PP%/*}
2970daaffb31Sdp		if [[ $PDIR == $PP ]]; then
29717c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
29727c478bd9Sstevel@tonic-gate		fi
29737c478bd9Sstevel@tonic-gate
29747c478bd9Sstevel@tonic-gate		PF=${PP##*/}
29757c478bd9Sstevel@tonic-gate
29767c478bd9Sstevel@tonic-gate		DIR=${P%/*}
2977daaffb31Sdp		if [[ $DIR == $P ]]; then
29787c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
29797c478bd9Sstevel@tonic-gate		fi
29807c478bd9Sstevel@tonic-gate
29817c478bd9Sstevel@tonic-gate		F=${P##*/}
2982daaffb31Sdp
29837c478bd9Sstevel@tonic-gate        else
29847c478bd9Sstevel@tonic-gate		DIR=${P%/*}
2985daaffb31Sdp		if [[ "$DIR" == "$P" ]]; then
29867c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
29877c478bd9Sstevel@tonic-gate		fi
29887c478bd9Sstevel@tonic-gate
29897c478bd9Sstevel@tonic-gate		F=${P##*/}
29907c478bd9Sstevel@tonic-gate
29917c478bd9Sstevel@tonic-gate		PP=$P
29927c478bd9Sstevel@tonic-gate		PDIR=$DIR
29937c478bd9Sstevel@tonic-gate		PF=$F
29947c478bd9Sstevel@tonic-gate	fi
29957c478bd9Sstevel@tonic-gate
2996daaffb31Sdp	COMM=`getcomments html $P $PP`
29977c478bd9Sstevel@tonic-gate
2998daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
30017c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
30027c478bd9Sstevel@tonic-gate
3003daaffb31Sdp	#
3004cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
3005daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
3006daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
3007daaffb31Sdp	#
3008daaffb31Sdp
3009cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
30107c478bd9Sstevel@tonic-gate	    continue
30117c478bd9Sstevel@tonic-gate
3012cdf0c1d5Smjnelson	#
3013cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3014cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3015cdf0c1d5Smjnelson	# consistent environment.
3016cdf0c1d5Smjnelson	#
3017cdf0c1d5Smjnelson	OWD=$PWD
3018daaffb31Sdp	cd $WDIR/raw_files
3019daaffb31Sdp	ofile=old/$PDIR/$PF
3020daaffb31Sdp	nfile=new/$DIR/$F
30217c478bd9Sstevel@tonic-gate
3022daaffb31Sdp	mv_but_nodiff=
3023daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3024daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3025daaffb31Sdp		mv_but_nodiff=1
3026daaffb31Sdp	fi
3027daaffb31Sdp
3028daaffb31Sdp	#
3029daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3030daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3031daaffb31Sdp	#
3032daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3033daaffb31Sdp	#	  diff and an 'add' diff
3034daaffb31Sdp	#	- new files and deleted files must be handled specially
3035daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
3036daaffb31Sdp	#	  (and hence renames) as of this writing.
3037daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
3038daaffb31Sdp	#	  output of Solaris diff properly when it comes to
3039daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
3040daaffb31Sdp	#         transformations:
3041daaffb31Sdp	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3042daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3043daaffb31Sdp	#
3044b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3045b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3046daaffb31Sdp
3047daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3048daaffb31Sdp	if [[ -z $rename ]]; then
3049e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3050daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3051daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3052e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3053daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3054daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3055daaffb31Sdp		else
3056daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3057daaffb31Sdp		fi
3058daaffb31Sdp	else
3059daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3060daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3061daaffb31Sdp
3062daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3063daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3064daaffb31Sdp	fi
3065daaffb31Sdp
3066daaffb31Sdp	#
3067daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3068daaffb31Sdp	# whole wad.
3069daaffb31Sdp	#
3070daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3071daaffb31Sdp
3072daaffb31Sdp	print " patch\c"
3073daaffb31Sdp
3074daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3075daaffb31Sdp
3076daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3077daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3078daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
30797c478bd9Sstevel@tonic-gate		print " cdiffs\c"
30807c478bd9Sstevel@tonic-gate
3081daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3082daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3083daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
3084daaffb31Sdp
30857c478bd9Sstevel@tonic-gate		print " udiffs\c"
30867c478bd9Sstevel@tonic-gate
30877c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3088daaffb31Sdp			$WDIFF -c "$COMM" \
3089daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3090daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3091daaffb31Sdp			if [[ $? -eq 0 ]]; then
30927c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3093daaffb31Sdp			else
3094daaffb31Sdp				print " wdiffs[fail]\c"
3095daaffb31Sdp			fi
30967c478bd9Sstevel@tonic-gate		fi
30977c478bd9Sstevel@tonic-gate
3098daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3099daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
31007c478bd9Sstevel@tonic-gate		print " sdiffs\c"
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate		print " frames\c"
31037c478bd9Sstevel@tonic-gate
31047c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
31057c478bd9Sstevel@tonic-gate
3106daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3107daaffb31Sdp
3108daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3109daaffb31Sdp		# renamed file: may also have differences
3110daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3111daaffb31Sdp	elif [[ -f $nfile ]]; then
31127c478bd9Sstevel@tonic-gate		# new file: count added lines
3113daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3114daaffb31Sdp	elif [[ -f $ofile ]]; then
31157c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3116daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
31177c478bd9Sstevel@tonic-gate	fi
31187c478bd9Sstevel@tonic-gate
3119daaffb31Sdp	#
3120daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3121daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3122daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3123daaffb31Sdp	#
3124daaffb31Sdp	if [[ -f $nfile ]]; then
3125daaffb31Sdp		ocr=$ofile
3126daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3127daaffb31Sdp
3128daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3129daaffb31Sdp			textcomm=`getcomments text $P $PP`
313014983201Sdp			if [[ -x $CODEREVIEW ]]; then
313114983201Sdp				$CODEREVIEW -y "$textcomm" \
313214983201Sdp				    -e $ocr $nfile \
313314983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
313414983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3135daaffb31Sdp				if [[ $? -eq 0 ]]; then
3136daaffb31Sdp					print " ps\c"
3137daaffb31Sdp				else
3138daaffb31Sdp					print " ps[fail]\c"
3139daaffb31Sdp				fi
3140daaffb31Sdp			fi
3141daaffb31Sdp		fi
314214983201Sdp	fi
3143daaffb31Sdp
3144cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3145cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
31467c478bd9Sstevel@tonic-gate		print " old\c"
31477c478bd9Sstevel@tonic-gate	fi
31487c478bd9Sstevel@tonic-gate
3149daaffb31Sdp	if [[ -f $nfile ]]; then
3150daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
31517c478bd9Sstevel@tonic-gate		print " new\c"
31527c478bd9Sstevel@tonic-gate	fi
31537c478bd9Sstevel@tonic-gate
3154cdf0c1d5Smjnelson	cd $OWD
3155cdf0c1d5Smjnelson
3156daaffb31Sdp	print
31577c478bd9Sstevel@tonic-gatedone
31587c478bd9Sstevel@tonic-gate
3159daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
31607c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3161daaffb31Sdp
316214983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
316314983201Sdp	print " Generating PDF: Skipped: no output available"
316414983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
316514983201Sdp	print " Generating PDF: \c"
316614983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3167daaffb31Sdp	print "Done."
316814983201Sdpelse
316914983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
317014983201Sdpfi
31717c478bd9Sstevel@tonic-gate
3172e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3173e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3174e0e0293aSjmcp
3175e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3176ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3177e0e0293aSjmcpfi
3178e0e0293aSjmcp
31797c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
31807c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
31817c478bd9Sstevel@tonic-gate
31827c478bd9Sstevel@tonic-gatecd $CWS
31837c478bd9Sstevel@tonic-gate
31847c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3185daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
31867c478bd9Sstevel@tonic-gate
3187daaffb31Sdpprint "     index.html: \c"
31887c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
31897c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
31907c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
31917c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
31927c478bd9Sstevel@tonic-gate
3193daaffb31Sdpprint "$HTML<head>$STDHEAD"
3194daaffb31Sdpprint "<title>$WNAME</title>"
3195daaffb31Sdpprint "</head>"
3196daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3197daaffb31Sdpprint "<div class=\"summary\">"
3198daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
31997c478bd9Sstevel@tonic-gate
3200daaffb31Sdpprint "<table>"
32017c478bd9Sstevel@tonic-gate
3202daaffb31Sdp#
3203cdf0c1d5Smjnelson# Get the preparer's name:
3204daaffb31Sdp#
3205cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3206cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3207cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3208cdf0c1d5Smjnelson#
3209cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3210cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3211cdf0c1d5Smjnelson#
3212cdf0c1d5Smjnelsonpreparer=
3213cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3214cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3215cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3216cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3217cdf0c1d5Smjnelson	fi
3218cdf0c1d5Smjnelsonfi
3219cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3220cdf0c1d5Smjnelson	preparer=$(
3221cdf0c1d5Smjnelson	    $PERL -e '
3222cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3223cdf0c1d5Smjnelson	        if ($login) {
3224cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3225cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3226cdf0c1d5Smjnelson	        } else {
3227cdf0c1d5Smjnelson	            printf "(unknown)\n";
3228cdf0c1d5Smjnelson	        }
3229cdf0c1d5Smjnelson	')
3230daaffb31Sdpfi
3231daaffb31Sdp
323248bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
323348bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
32348bcea973SRichard Loweprint "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3235cdf0c1d5Smjnelsonprint "</td></tr>"
3236daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3237daaffb31Sdpif [[ -n $parent_webrev ]]; then
3238daaffb31Sdp	print "webrev at $parent_webrev"
3239daaffb31Sdpelse
32408bcea973SRichard Lowe	print "${PRETTY_PWS:-$PWS}"
3241daaffb31Sdpfi
3242daaffb31Sdpprint "</td></tr>"
3243daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3244daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3245daaffb31Sdpprint "</td></tr>"
3246daaffb31Sdp
3247daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3248371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3249daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3250371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3251daaffb31Sdpfi
3252daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3253371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3254daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3255371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3256daaffb31Sdpfi
3257daaffb31Sdp
3258daaffb31Sdpif [[ -n "$iflag" ]]; then
3259daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3260daaffb31Sdp	cat /tmp/$$.include
3261daaffb31Sdp	print "</div></td></tr>"
3262daaffb31Sdpfi
3263daaffb31Sdpprint "</table>"
3264daaffb31Sdpprint "</div>"
3265daaffb31Sdp
3266daaffb31Sdp#
3267daaffb31Sdp# Second pass through the files: generate the rest of the index file
3268daaffb31Sdp#
3269daaffb31Sdpcat $FLIST | while read LINE
32707c478bd9Sstevel@tonic-gatedo
32717c478bd9Sstevel@tonic-gate	set - $LINE
32727c478bd9Sstevel@tonic-gate	P=$1
32737c478bd9Sstevel@tonic-gate
3274daaffb31Sdp	if [[ $# == 2 ]]; then
32757c478bd9Sstevel@tonic-gate		PP=$2
3276cdf0c1d5Smjnelson		oldname="$PP"
32777c478bd9Sstevel@tonic-gate	else
32787c478bd9Sstevel@tonic-gate		PP=$P
3279daaffb31Sdp		oldname=""
3280daaffb31Sdp	fi
3281daaffb31Sdp
3282cdf0c1d5Smjnelson	mv_but_nodiff=
3283cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3284cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3285cdf0c1d5Smjnelson		mv_but_nodiff=1
3286cdf0c1d5Smjnelson	fi
3287cdf0c1d5Smjnelson
3288daaffb31Sdp	DIR=${P%/*}
3289daaffb31Sdp	if [[ $DIR == $P ]]; then
3290daaffb31Sdp		DIR="."   # File at root of workspace
32917c478bd9Sstevel@tonic-gate	fi
32927c478bd9Sstevel@tonic-gate
32937c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
32947c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
32957c478bd9Sstevel@tonic-gate	# appear twice in the file list
32967c478bd9Sstevel@tonic-gate
32977c478bd9Sstevel@tonic-gate	F=$WDIR/$P
32987c478bd9Sstevel@tonic-gate
3299daaffb31Sdp	print "<p>"
33007c478bd9Sstevel@tonic-gate
33017c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
33027c478bd9Sstevel@tonic-gate
3303daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3304371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3305371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3306371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3307371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
33087c478bd9Sstevel@tonic-gate
3309daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3310371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3311371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
33127c478bd9Sstevel@tonic-gate		fi
33137c478bd9Sstevel@tonic-gate
3314371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3315371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
33167c478bd9Sstevel@tonic-gate
3317371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3318371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
33197c478bd9Sstevel@tonic-gate	else
3320daaffb31Sdp		print " ------ ------ ------"
33217c478bd9Sstevel@tonic-gate
3322daaffb31Sdp		if [[ -x $WDIFF ]]; then
33237c478bd9Sstevel@tonic-gate			print " ------"
33247c478bd9Sstevel@tonic-gate		fi
3325daaffb31Sdp
3326daaffb31Sdp		print " ------"
33277c478bd9Sstevel@tonic-gate	fi
33287c478bd9Sstevel@tonic-gate
33297c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
33307c478bd9Sstevel@tonic-gate
3331daaffb31Sdp	if [[ -f $F-.html ]]; then
3332371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3333371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
33347c478bd9Sstevel@tonic-gate	else
3335daaffb31Sdp		print " ---"
33367c478bd9Sstevel@tonic-gate	fi
33377c478bd9Sstevel@tonic-gate
33387c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
33397c478bd9Sstevel@tonic-gate
3340daaffb31Sdp	if [[ -f $F.html ]]; then
3341371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3342371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
33437c478bd9Sstevel@tonic-gate	else
3344daaffb31Sdp		print " ---"
33457c478bd9Sstevel@tonic-gate	fi
33467c478bd9Sstevel@tonic-gate
3347daaffb31Sdp	if [[ -f $F.patch ]]; then
3348371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3349371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3350daaffb31Sdp	else
3351daaffb31Sdp		print " -----"
3352daaffb31Sdp	fi
3353daaffb31Sdp
3354daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3355371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3356371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3357daaffb31Sdp	else
3358daaffb31Sdp		print " ---"
3359daaffb31Sdp	fi
3360daaffb31Sdp
3361cdf0c1d5Smjnelson	print "<b>$P</b>"
3362cdf0c1d5Smjnelson
3363cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3364e6ccc173SEdward Pilatowicz	if [[ -f "$oldname" ]]; then
3365cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3366e6ccc173SEdward Pilatowicz			print "<i>(copied from $oldname)</i>"
3367cdf0c1d5Smjnelson		else
3368e6ccc173SEdward Pilatowicz			print "<i>(copied and modified from $oldname)</i>"
3369e6ccc173SEdward Pilatowicz		fi
3370e6ccc173SEdward Pilatowicz	elif [[ -n "$oldname" ]]; then
3371e6ccc173SEdward Pilatowicz		if [[ -n "$mv_but_nodiff" ]]; then
3372e6ccc173SEdward Pilatowicz			print "<i>(renamed from $oldname)</i>"
3373e6ccc173SEdward Pilatowicz		else
3374e6ccc173SEdward Pilatowicz			print "<i>(renamed and modified from $oldname)</i>"
3375cdf0c1d5Smjnelson		fi
3376cdf0c1d5Smjnelson	fi
3377cdf0c1d5Smjnelson
3378cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3379cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3380cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3381cdf0c1d5Smjnelson	fi
3382daaffb31Sdp
3383daaffb31Sdp	#
3384e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3385daaffb31Sdp	#
3386daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3387e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3388e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3389daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3390daaffb31Sdp			    "this review</i>"
3391daaffb31Sdp		fi
3392daaffb31Sdp	fi
3393daaffb31Sdp
3394daaffb31Sdp	print "</p>"
33957c478bd9Sstevel@tonic-gate	# Insert delta comments
33967c478bd9Sstevel@tonic-gate
3397daaffb31Sdp	print "<blockquote><pre>"
3398daaffb31Sdp	getcomments html $P $PP
3399daaffb31Sdp	print "</pre>"
34007c478bd9Sstevel@tonic-gate
34017c478bd9Sstevel@tonic-gate	# Add additional comments comment
34027c478bd9Sstevel@tonic-gate
3403daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
34047c478bd9Sstevel@tonic-gate
34057c478bd9Sstevel@tonic-gate	# Add count of changes.
34067c478bd9Sstevel@tonic-gate
3407daaffb31Sdp	if [[ -f $F.count ]]; then
34087c478bd9Sstevel@tonic-gate	    cat $F.count
34097c478bd9Sstevel@tonic-gate	    rm $F.count
34107c478bd9Sstevel@tonic-gate	fi
3411cdf0c1d5Smjnelson
3412d7b56f41SBart Coddens	if [[ $SCM_MODE == "mercurial" ||
3413cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3414cdf0c1d5Smjnelson
3415cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3416cdf0c1d5Smjnelson		# 1) New executable files
3417cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3418cdf0c1d5Smjnelson		# 3) Existing executable files
3419cdf0c1d5Smjnelson
3420cdf0c1d5Smjnelson		old_mode=
3421cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3422cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3423cdf0c1d5Smjnelson		fi
3424cdf0c1d5Smjnelson
3425cdf0c1d5Smjnelson		new_mode=
3426cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3427cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3428cdf0c1d5Smjnelson		fi
3429cdf0c1d5Smjnelson
3430cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3431cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3432cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3433cdf0c1d5Smjnelson			print "</span>"
3434cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3435cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3436cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3437cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3438cdf0c1d5Smjnelson			print "</span>"
3439cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3440cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3441cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3442cdf0c1d5Smjnelson			print "</span>"
3443cdf0c1d5Smjnelson		fi
3444cdf0c1d5Smjnelson	fi
3445cdf0c1d5Smjnelson
3446daaffb31Sdp	print "</blockquote>"
34477c478bd9Sstevel@tonic-gatedone
34487c478bd9Sstevel@tonic-gate
3449daaffb31Sdpprint
3450daaffb31Sdpprint
3451cac38512Smjnelsonprint "<hr></hr>"
3452daaffb31Sdpprint "<p style=\"font-size: small\">"
34539a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
345487a4464eSChris Loveprint "Webrev is maintained by the <a href=\"http://www.illumos.org\">"
345587a4464eSChris Loveprint "illumos</a> project.  The latest version may be obtained"
34567646c8f3SMarcel Telkaprint "<a href=\"http://src.illumos.org/source/xref/illumos-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3457daaffb31Sdpprint "</body>"
3458daaffb31Sdpprint "</html>"
34597c478bd9Sstevel@tonic-gate
34607c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
34617c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
34627c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
34637c478bd9Sstevel@tonic-gate
3464daaffb31Sdpprint "Done."
346502d26c39SVladimir Kotal
3466b0088928SVladimir Kotal#
3467ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3468b0088928SVladimir Kotal#
3469ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3470b0088928SVladimir Kotal	delete_webrev 1 1
3471ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3472ba44d8a2SVladimir Kotalfi
3473ba44d8a2SVladimir Kotal
347402d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
347502d26c39SVladimir Kotal	upload_webrev
347602d26c39SVladimir Kotal	exit $?
347702d26c39SVladimir Kotalfi
3478