xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 0fd2682eef78b1fd2fbb5d69ccc03968820967ae)
17c478bd9Sstevel@tonic-gate#!/usr/bin/ksh -p
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6daaffb31Sdp# Common Development and Distribution License (the "License").
7daaffb31Sdp# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
229a70fc3bSMark J. Nelson
237c478bd9Sstevel@tonic-gate#
24371d72daSLubomir Sedlacik# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate# Use is subject to license terms.
267c478bd9Sstevel@tonic-gate#
27cdf0c1d5Smjnelson
28cdf0c1d5Smjnelson#
29daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
30daaffb31Sdp# suitable for doing a code review of source changes via a web page.
31daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
32daaffb31Sdp# type 'webrev -h'.
337c478bd9Sstevel@tonic-gate#
34daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
35daaffb31Sdp# man page.
367c478bd9Sstevel@tonic-gate#
37daaffb31Sdp
387c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
397c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
407c478bd9Sstevel@tonic-gateNEW_COLOR=blue
417c478bd9Sstevel@tonic-gate
42daaffb31SdpHTML='<?xml version="1.0"?>
43daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
44daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
45daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
46daaffb31Sdp
47daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
48daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
49daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
50daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
51daaffb31Sdp
52cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
53cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
54cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
55daaffb31Sdp<!--
56daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
57daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
58daaffb31Sdp   mechanism available in some browsers.
59daaffb31Sdp
60daaffb31Sdp   For example, to have all "removed" information be red instead of
61daaffb31Sdp   brown, set a rule in your userContent.css file like:
62daaffb31Sdp
63daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
64daaffb31Sdp-->
65daaffb31Sdp<style type="text/css" media="screen">
66daaffb31Sdpbody {
67daaffb31Sdp    background-color: #eeeeee;
68daaffb31Sdp}
69daaffb31Sdphr {
70daaffb31Sdp    border: none 0;
71daaffb31Sdp    border-top: 1px solid #aaa;
72daaffb31Sdp    height: 1px;
73daaffb31Sdp}
74daaffb31Sdpdiv.summary {
75daaffb31Sdp    font-size: .8em;
76daaffb31Sdp    border-bottom: 1px solid #aaa;
77daaffb31Sdp    padding-left: 1em;
78daaffb31Sdp    padding-right: 1em;
79daaffb31Sdp}
80daaffb31Sdpdiv.summary h2 {
81daaffb31Sdp    margin-bottom: 0.3em;
82daaffb31Sdp}
83daaffb31Sdpdiv.summary table th {
84daaffb31Sdp    text-align: right;
85daaffb31Sdp    vertical-align: top;
86daaffb31Sdp    white-space: nowrap;
87daaffb31Sdp}
88daaffb31Sdpspan.lineschanged {
89daaffb31Sdp    font-size: 0.7em;
90daaffb31Sdp}
91daaffb31Sdpspan.oldmarker {
92daaffb31Sdp    color: red;
93daaffb31Sdp    font-size: large;
94daaffb31Sdp    font-weight: bold;
95daaffb31Sdp}
96daaffb31Sdpspan.newmarker {
97daaffb31Sdp    color: green;
98daaffb31Sdp    font-size: large;
99daaffb31Sdp    font-weight: bold;
100daaffb31Sdp}
101daaffb31Sdpspan.removed {
102daaffb31Sdp    color: brown;
103daaffb31Sdp}
104daaffb31Sdpspan.changed {
105daaffb31Sdp    color: blue;
106daaffb31Sdp}
107daaffb31Sdpspan.new {
108daaffb31Sdp    color: blue;
109daaffb31Sdp    font-weight: bold;
110daaffb31Sdp}
111cdf0c1d5Smjnelsonspan.chmod {
112cdf0c1d5Smjnelson    font-size: 0.7em;
113cdf0c1d5Smjnelson    color: #db7800;
114cdf0c1d5Smjnelson}
115daaffb31Sdpa.print { font-size: x-small; }
116daaffb31Sdpa:hover { background-color: #ffcc99; }
117daaffb31Sdp</style>
118daaffb31Sdp
119daaffb31Sdp<style type="text/css" media="print">
120daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
121daaffb31Sdpspan.removed { color: #444; font-style: italic }
122daaffb31Sdpspan.changed { font-weight: bold; }
123daaffb31Sdpspan.new { font-weight: bold; }
124daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
125daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
126daaffb31Sdpa.print {display: none}
127daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
128daaffb31Sdp</style>
129daaffb31Sdp'
130daaffb31Sdp
131daaffb31Sdp#
132daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
133daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
134daaffb31Sdp#
135daaffb31SdpUDIFFCSS='
136daaffb31Sdp<style type="text/css" media="screen">
137daaffb31Sdpspan.new {
138daaffb31Sdp    color: blue;
139daaffb31Sdp    font-weight: normal;
140daaffb31Sdp}
141daaffb31Sdp</style>
142daaffb31Sdp'
143daaffb31Sdp
144b0088928SVladimir Kotal#
145b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
146b0088928SVladimir Kotal#
147b0088928SVladimir Kotalfunction print_upload_header
148b0088928SVladimir Kotal{
149b0088928SVladimir Kotal	typeset -r prefix=$1
150b0088928SVladimir Kotal	typeset display_target
151b0088928SVladimir Kotal
152b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
153b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
154b0088928SVladimir Kotal	else
155b0088928SVladimir Kotal		display_target=${remote_target}
156b0088928SVladimir Kotal	fi
157b0088928SVladimir Kotal
158b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
159b0088928SVladimir Kotal		display_target=${display_target}/
160b0088928SVladimir Kotal	fi
161b0088928SVladimir Kotal
162b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
163b0088928SVladimir Kotal	    "     Uploading: \c"
164b0088928SVladimir Kotal}
165b0088928SVladimir Kotal
166b0088928SVladimir Kotal#
16702d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
168b0088928SVladimir Kotal#
169ba44d8a2SVladimir Kotalfunction rsync_upload
17002d26c39SVladimir Kotal{
171b0088928SVladimir Kotal	if (( $# != 2 )); then
172b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
173b0088928SVladimir Kotal		exit 1
17402d26c39SVladimir Kotal	fi
17502d26c39SVladimir Kotal
176b0088928SVladimir Kotal	typeset -r dst=$1
177b0088928SVladimir Kotal	integer -r print_err_msg=$2
17802d26c39SVladimir Kotal
179b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
180b0088928SVladimir Kotal	print "rsync ... \c"
181b0088928SVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXX )
182b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
183b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
184b0088928SVladimir Kotal		return 1
185b0088928SVladimir Kotal	fi
186b0088928SVladimir Kotal	#
187b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
188b0088928SVladimir Kotal	# directory contents, not the whole directory.
189b0088928SVladimir Kotal	#
190b0088928SVladimir Kotal	typeset src_dir=$WDIR
191b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
192b0088928SVladimir Kotal		src_dir=${src_dir}/
193b0088928SVladimir Kotal	fi
194b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
19502d26c39SVladimir Kotal	if (( $? != 0 )); then
196b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
197b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
198b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
199b0088928SVladimir Kotal			print "error messages:"
200b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
201b0088928SVladimir Kotal			rm -f $err_msg
202b0088928SVladimir Kotal		fi
20302d26c39SVladimir Kotal		return 1
20402d26c39SVladimir Kotal	fi
20502d26c39SVladimir Kotal
206b0088928SVladimir Kotal	rm -f $err_msg
20702d26c39SVladimir Kotal	print "Done."
20802d26c39SVladimir Kotal	return 0
20902d26c39SVladimir Kotal}
21002d26c39SVladimir Kotal
211b0088928SVladimir Kotal#
212b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
213b0088928SVladimir Kotal# 1 on failure.
214b0088928SVladimir Kotal#
215b0088928SVladimir Kotalfunction remote_mkdirs
216b0088928SVladimir Kotal{
217b0088928SVladimir Kotal	typeset -r dir_spec=$1
218b0088928SVladimir Kotal
219b0088928SVladimir Kotal	#
220b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
221b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
222b0088928SVladimir Kotal	# except the last one which will be created by scp.
223b0088928SVladimir Kotal	#
224b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
225b0088928SVladimir Kotal		print "mkdirs \c"
226b0088928SVladimir Kotal		#
227b0088928SVladimir Kotal		# Remove the last directory from directory specification.
228b0088928SVladimir Kotal		#
229b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
230b0088928SVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP /tmp/webrev_mkdir.XXX )
231b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
232b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
233b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
234b0088928SVladimir Kotal			return 1
235b0088928SVladimir Kotal		fi
236b0088928SVladimir Kotal                OLDIFS=$IFS
237b0088928SVladimir Kotal                IFS=/
238b0088928SVladimir Kotal		typeset dir
239b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
240b0088928SVladimir Kotal			#
241b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
242b0088928SVladimir Kotal			# to avoid an error in case the directory already
243b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
244b0088928SVladimir Kotal			# there is one.
245b0088928SVladimir Kotal			#
246b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
247b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
248b0088928SVladimir Kotal                done
249b0088928SVladimir Kotal                IFS=$OLDIFS
250b0088928SVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXX )
251b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
252b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
253b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
254b0088928SVladimir Kotal			return 1
255b0088928SVladimir Kotal		fi
256b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
257b0088928SVladimir Kotal		if (( $? != 0 )); then
258b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
259b0088928SVladimir Kotal			print "error messages:"
260b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
261b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
262b0088928SVladimir Kotal			return 1
263b0088928SVladimir Kotal		fi
264b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
265b0088928SVladimir Kotal	fi
266b0088928SVladimir Kotal
267b0088928SVladimir Kotal	return 0
268b0088928SVladimir Kotal}
269b0088928SVladimir Kotal
270b0088928SVladimir Kotal#
27102d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
272b0088928SVladimir Kotal#
273ba44d8a2SVladimir Kotalfunction ssh_upload
27402d26c39SVladimir Kotal{
27502d26c39SVladimir Kotal	if (( $# != 1 )); then
276b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
277b0088928SVladimir Kotal		exit 1
27802d26c39SVladimir Kotal	fi
27902d26c39SVladimir Kotal
28002d26c39SVladimir Kotal	typeset dst=$1
28102d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
282ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
28302d26c39SVladimir Kotal
284b0088928SVladimir Kotal	#
285b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
286b0088928SVladimir Kotal	# because it will also print its progress.
287b0088928SVladimir Kotal	#
288b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
289b0088928SVladimir Kotal
290b0088928SVladimir Kotal	#
291b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
292b0088928SVladimir Kotal	# to perform it again.
293b0088928SVladimir Kotal	#
294ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
295b0088928SVladimir Kotal		#
296b0088928SVladimir Kotal		# We do not care about return value because this might be
297b0088928SVladimir Kotal		# the first time this directory is uploaded.
298b0088928SVladimir Kotal		#
299ba44d8a2SVladimir Kotal		delete_webrev 0
30002d26c39SVladimir Kotal	fi
30102d26c39SVladimir Kotal
302b0088928SVladimir Kotal	#
303b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
304b0088928SVladimir Kotal	# in remote_mkdirs function.
305b0088928SVladimir Kotal	#
306b0088928SVladimir Kotal	remote_mkdirs ${dir_spec}
30702d26c39SVladimir Kotal	if (( $? != 0 )); then
30802d26c39SVladimir Kotal		return 1
30902d26c39SVladimir Kotal	fi
31002d26c39SVladimir Kotal
311b0088928SVladimir Kotal	print "upload ... \c"
312b0088928SVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXX )
313b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
314b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
315b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
316b0088928SVladimir Kotal		return 1
317b0088928SVladimir Kotal	fi
31802d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
319b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
32002d26c39SVladimir Kotal	if (( $? != 0 )); then
321b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
322b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
323b0088928SVladimir Kotal		print "error messages:"
324b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
325b0088928SVladimir Kotal		rm -f ${scp_err_msg}
32602d26c39SVladimir Kotal		return 1
32702d26c39SVladimir Kotal	fi
32802d26c39SVladimir Kotal
329b0088928SVladimir Kotal	rm -f ${scp_err_msg}
33002d26c39SVladimir Kotal	print "Done."
33102d26c39SVladimir Kotal	return 0
33202d26c39SVladimir Kotal}
33302d26c39SVladimir Kotal
33402d26c39SVladimir Kotal#
335ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
336b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
337b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
338b0088928SVladimir Kotal# only performs deletion.
339ba44d8a2SVladimir Kotal#
340ba44d8a2SVladimir Kotalfunction delete_webrev
341ba44d8a2SVladimir Kotal{
342b0088928SVladimir Kotal	if (( $# < 1 )); then
343b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
344b0088928SVladimir Kotal		exit 1
345ba44d8a2SVladimir Kotal	fi
346ba44d8a2SVladimir Kotal
347b0088928SVladimir Kotal	integer -r check=$1
348b0088928SVladimir Kotal	integer delete_only=0
349b0088928SVladimir Kotal	if (( $# == 2 )); then
350b0088928SVladimir Kotal		delete_only=1
351b0088928SVladimir Kotal	fi
352b0088928SVladimir Kotal
353b0088928SVladimir Kotal	#
354ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
355b0088928SVladimir Kotal	#
356ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
357ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
358ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
359ba44d8a2SVladimir Kotal	typeset dir_rm
360ba44d8a2SVladimir Kotal
361b0088928SVladimir Kotal	#
362ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
363b0088928SVladimir Kotal	#
364ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
365ba44d8a2SVladimir Kotal		return 1
366ba44d8a2SVladimir Kotal	fi
367ba44d8a2SVladimir Kotal
368b0088928SVladimir Kotal	#
369ba44d8a2SVladimir Kotal	# Strip the ending slash.
370b0088928SVladimir Kotal	#
371ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
372ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
373ba44d8a2SVladimir Kotal	else
374ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
375ba44d8a2SVladimir Kotal	fi
376ba44d8a2SVladimir Kotal
377b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
378b0088928SVladimir Kotal		print "       Removing: \c"
379b0088928SVladimir Kotal	else
380b0088928SVladimir Kotal		print "rmdir \c"
381b0088928SVladimir Kotal	fi
382ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
383b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
384ba44d8a2SVladimir Kotal		return 1
385ba44d8a2SVladimir Kotal	fi
386ba44d8a2SVladimir Kotal
387b0088928SVladimir Kotal	#
388ba44d8a2SVladimir Kotal	# Prepare batch file.
389b0088928SVladimir Kotal	#
390ba44d8a2SVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXX )
391ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
392b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
393ba44d8a2SVladimir Kotal		return 1
394ba44d8a2SVladimir Kotal	fi
395ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
396ba44d8a2SVladimir Kotal
397b0088928SVladimir Kotal	#
398ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
399b0088928SVladimir Kotal	#
400b0088928SVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXX )
401b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
402b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
403b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
404b0088928SVladimir Kotal		return 1
405b0088928SVladimir Kotal	fi
406b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
407ba44d8a2SVladimir Kotal	integer -r ret=$?
408ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
409ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
410b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
411b0088928SVladimir Kotal		print "error messages:"
412b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
413b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
414ba44d8a2SVladimir Kotal		return $ret
415ba44d8a2SVladimir Kotal	fi
416b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
417b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
418ba44d8a2SVladimir Kotal		print "Done."
419b0088928SVladimir Kotal	fi
420ba44d8a2SVladimir Kotal
421ba44d8a2SVladimir Kotal	return 0
422ba44d8a2SVladimir Kotal}
423ba44d8a2SVladimir Kotal
424ba44d8a2SVladimir Kotal#
42502d26c39SVladimir Kotal# Upload webrev to remote site
42602d26c39SVladimir Kotal#
427ba44d8a2SVladimir Kotalfunction upload_webrev
42802d26c39SVladimir Kotal{
429b0088928SVladimir Kotal	integer ret
43002d26c39SVladimir Kotal
43102d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
432b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
43302d26c39SVladimir Kotal		return 1
43402d26c39SVladimir Kotal	fi
43502d26c39SVladimir Kotal
436b0088928SVladimir Kotal	#
43702d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
43802d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
43902d26c39SVladimir Kotal	# target he probably knows what he is doing.
440b0088928SVladimir Kotal	#
44102d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
442ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
44302d26c39SVladimir Kotal			| $GREP closed >/dev/null
44402d26c39SVladimir Kotal		if (( $? == 0 )); then
445b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
446b0088928SVladimir Kotal			    "\"closed\" directory"
44702d26c39SVladimir Kotal			return 1
44802d26c39SVladimir Kotal		fi
44902d26c39SVladimir Kotal	fi
45002d26c39SVladimir Kotal
451b0088928SVladimir Kotal
452b0088928SVladimir Kotal	#
453b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
454b0088928SVladimir Kotal	#
45502d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
45602d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
457b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
458b0088928SVladimir Kotal			ret=$?
459b0088928SVladimir Kotal			return $ret
46002d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
46102d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
462b0088928SVladimir Kotal			ret=$?
463b0088928SVladimir Kotal			return $ret
46402d26c39SVladimir Kotal		fi
46502d26c39SVladimir Kotal	else
466b0088928SVladimir Kotal		#
467b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
468b0088928SVladimir Kotal		#
469b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
470b0088928SVladimir Kotal		ret=$?
471b0088928SVladimir Kotal		if (( $ret != 0 )); then
472b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
473ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
474b0088928SVladimir Kotal			ret=$?
47502d26c39SVladimir Kotal		fi
476b0088928SVladimir Kotal		return $ret
47702d26c39SVladimir Kotal	fi
47802d26c39SVladimir Kotal}
47902d26c39SVladimir Kotal
480daaffb31Sdp#
481371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
482371d72daSLubomir Sedlacik#
483371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
484371d72daSLubomir Sedlacik#
485371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
486371d72daSLubomir Sedlacik#
487371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
488371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
489371d72daSLubomir Sedlacik# a path delimiter.
490371d72daSLubomir Sedlacik#
491371d72daSLubomir Sedlacikfunction url_encode
492371d72daSLubomir Sedlacik{
493b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
494371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
495371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
496371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
497371d72daSLubomir Sedlacik	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|\'|%27|g" \
498371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
499371d72daSLubomir Sedlacik}
500371d72daSLubomir Sedlacik
501371d72daSLubomir Sedlacik#
502daaffb31Sdp# input_cmd | html_quote | output_cmd
503daaffb31Sdp# or
504daaffb31Sdp# html_quote filename | output_cmd
5057c478bd9Sstevel@tonic-gate#
5067c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5077c478bd9Sstevel@tonic-gate#
5087c478bd9Sstevel@tonic-gatehtml_quote()
5097c478bd9Sstevel@tonic-gate{
510b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5117c478bd9Sstevel@tonic-gate}
5127c478bd9Sstevel@tonic-gate
513daaffb31Sdp#
514*0fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
515daaffb31Sdp#
516*0fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
517*0fd2682eSMark J. Nelson# relevant databases.
518daaffb31Sdp#
519*0fd2682eSMark J. Nelsonits2url()
5207c478bd9Sstevel@tonic-gate{
521*0fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
522daaffb31Sdp}
523daaffb31Sdp
5247c478bd9Sstevel@tonic-gate#
525daaffb31Sdp# strip_unchanged <infile> | output_cmd
5267c478bd9Sstevel@tonic-gate#
527daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
528daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5297c478bd9Sstevel@tonic-gate#
530daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
531daaffb31Sdp# identical lines are retained before and after the changed lines to
532daaffb31Sdp# provide some context.  The number of these lines is controlled by the
533cdf0c1d5Smjnelson# variable C in the $AWK script below.
534daaffb31Sdp#
535daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
536daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
537daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
538daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
539daaffb31Sdp#
540daaffb31Sdpstrip_unchanged()
541daaffb31Sdp{
542cdf0c1d5Smjnelson	$AWK '
543daaffb31Sdp	BEGIN	{ C = c = 20 }
544cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
545daaffb31Sdp		if (c > C) {
546daaffb31Sdp			c -= C
547daaffb31Sdp			inx = 0
548daaffb31Sdp			if (c > C) {
549cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
550daaffb31Sdp				inx = c % C
551daaffb31Sdp				c = C
552daaffb31Sdp			}
553daaffb31Sdp
554daaffb31Sdp			for (i = 0; i < c; i++)
555daaffb31Sdp				print ln[(inx + i) % C]
556daaffb31Sdp		}
557daaffb31Sdp		c = 0;
558daaffb31Sdp		print
559daaffb31Sdp		next
560daaffb31Sdp	}
561daaffb31Sdp	{	if (c >= C) {
562daaffb31Sdp			ln[c % C] = $0
563daaffb31Sdp			c++;
564daaffb31Sdp			next;
565daaffb31Sdp		}
566daaffb31Sdp		c++;
567daaffb31Sdp		print
568daaffb31Sdp	}
569cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
570daaffb31Sdp
571daaffb31Sdp	' $1
572daaffb31Sdp}
573daaffb31Sdp
574daaffb31Sdp#
575daaffb31Sdp# sdiff_to_html
576daaffb31Sdp#
577daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
578daaffb31Sdp# processes the diff output to present the files as an HTML document with
579daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
580daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
581daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
582daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
583daaffb31Sdp# e.g.
584daaffb31Sdp#
585daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
586daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
587daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
588daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
589daaffb31Sdp#          1234567</a> my bugid' > <file>.html
590daaffb31Sdp#
591daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
592daaffb31Sdp# in the webrev tree.
593daaffb31Sdp#
594daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
595daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
596daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
597daaffb31Sdp# the editing codes, e.g.
5987c478bd9Sstevel@tonic-gate#
5997c478bd9Sstevel@tonic-gate#      8c8
6007c478bd9Sstevel@tonic-gate#      57a61
6017c478bd9Sstevel@tonic-gate#      63c66,76
6027c478bd9Sstevel@tonic-gate#      68,93d80
6037c478bd9Sstevel@tonic-gate#      106d90
6047c478bd9Sstevel@tonic-gate#      108,110d91
6057c478bd9Sstevel@tonic-gate#
606daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
607daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
608daaffb31Sdp#  into something like this:
6097c478bd9Sstevel@tonic-gate#
6107c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6117c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
612daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6137c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6147c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6157c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6167c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6177c478bd9Sstevel@tonic-gate#        :               :
6187c478bd9Sstevel@tonic-gate#
619daaffb31Sdp#  This script is then run on the original source file to generate the
620daaffb31Sdp#  HTML that corresponds to the source file.
6217c478bd9Sstevel@tonic-gate#
622daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
623daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
624daaffb31Sdp#  notice that the changes are color-coded:
6257c478bd9Sstevel@tonic-gate#
6267c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6277c478bd9Sstevel@tonic-gate#   blue      - changed lines
6287c478bd9Sstevel@tonic-gate#   bold blue - new lines
6297c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6307c478bd9Sstevel@tonic-gate#
631daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
632daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
633daaffb31Sdp#  Teamware's filemerge tool.
634daaffb31Sdp#
635daaffb31Sdpsdiff_to_html()
636daaffb31Sdp{
6377c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6387c478bd9Sstevel@tonic-gate
639daaffb31Sdp	TNAME=$3
640daaffb31Sdp	TPATH=$4
641daaffb31Sdp	COMMENT=$5
642daaffb31Sdp
6437c478bd9Sstevel@tonic-gate	#
6447c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6457c478bd9Sstevel@tonic-gate	#
646cdf0c1d5Smjnelson	$AWK '
6477c478bd9Sstevel@tonic-gate	BEGIN	{
6487c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
649daaffb31Sdp		printf "function removed() "
650daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
651daaffb31Sdp		printf "function changed() "
652daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
653daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6547c478bd9Sstevel@tonic-gate}
6557c478bd9Sstevel@tonic-gate	/^</	{next}
6567c478bd9Sstevel@tonic-gate	/^>/	{next}
6577c478bd9Sstevel@tonic-gate	/^---/	{next}
658daaffb31Sdp
6597c478bd9Sstevel@tonic-gate	{
6607c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6617c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6627c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6637c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6647c478bd9Sstevel@tonic-gate			if (n == 1)
6657c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6667c478bd9Sstevel@tonic-gate			else
6677c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6687c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6697c478bd9Sstevel@tonic-gate			next
6707c478bd9Sstevel@tonic-gate		}
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6737c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6747c478bd9Sstevel@tonic-gate		s = r[1];
6757c478bd9Sstevel@tonic-gate		if (n == 1)
6767c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6777c478bd9Sstevel@tonic-gate		else {
6787c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6797c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6807c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6817c478bd9Sstevel@tonic-gate		}
6827c478bd9Sstevel@tonic-gate		next
6837c478bd9Sstevel@tonic-gate	}
6847c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
6857c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
6867c478bd9Sstevel@tonic-gate		n1 = r[1]
6877c478bd9Sstevel@tonic-gate		n2 = r[2]
6887c478bd9Sstevel@tonic-gate		if (n == 1)
689daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
6907c478bd9Sstevel@tonic-gate		else
691daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
6927c478bd9Sstevel@tonic-gate		next
6937c478bd9Sstevel@tonic-gate	}
6947c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
6957c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
6967c478bd9Sstevel@tonic-gate		n1 = r[1]
6977c478bd9Sstevel@tonic-gate		n2 = r[2]
6987c478bd9Sstevel@tonic-gate		final = n2
6997c478bd9Sstevel@tonic-gate		d1 = 0
7007c478bd9Sstevel@tonic-gate		if (n == 1)
701daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7027c478bd9Sstevel@tonic-gate		else {
7037c478bd9Sstevel@tonic-gate			d1 = n2 - n1
704daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7057c478bd9Sstevel@tonic-gate		}
7067c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7077c478bd9Sstevel@tonic-gate		n1 = r[1]
7087c478bd9Sstevel@tonic-gate		n2 = r[2]
7097c478bd9Sstevel@tonic-gate		if (m > 1) {
7107c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7117c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7127c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7137c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7147c478bd9Sstevel@tonic-gate			}
7157c478bd9Sstevel@tonic-gate		}
7167c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate		next
7197c478bd9Sstevel@tonic-gate	}
7207c478bd9Sstevel@tonic-gate	}
7217c478bd9Sstevel@tonic-gate
722daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
723daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate	#
7267c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7277c478bd9Sstevel@tonic-gate	#
728cdf0c1d5Smjnelson	$AWK '
7297c478bd9Sstevel@tonic-gate	BEGIN	{
7307c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
731daaffb31Sdp		printf "function new() "
732daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
733daaffb31Sdp		printf "function changed() "
734daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
735daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7367c478bd9Sstevel@tonic-gate	}
737daaffb31Sdp
7387c478bd9Sstevel@tonic-gate	/^</	{next}
7397c478bd9Sstevel@tonic-gate	/^>/	{next}
7407c478bd9Sstevel@tonic-gate	/^---/	{next}
741daaffb31Sdp
7427c478bd9Sstevel@tonic-gate	{
7437c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7447c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7457c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7467c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7477c478bd9Sstevel@tonic-gate			if (n == 1)
7487c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7497c478bd9Sstevel@tonic-gate			else
7507c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7517c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7527c478bd9Sstevel@tonic-gate			next
7537c478bd9Sstevel@tonic-gate		}
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7567c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7577c478bd9Sstevel@tonic-gate		s = r[1];
7587c478bd9Sstevel@tonic-gate		if (n == 1)
7597c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7607c478bd9Sstevel@tonic-gate		else {
7617c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7627c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7637c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7647c478bd9Sstevel@tonic-gate		}
7657c478bd9Sstevel@tonic-gate		next
7667c478bd9Sstevel@tonic-gate	}
7677c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7687c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7697c478bd9Sstevel@tonic-gate		n1 = r[1]
7707c478bd9Sstevel@tonic-gate		n2 = r[2]
7717c478bd9Sstevel@tonic-gate		if (n == 1)
772daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7737c478bd9Sstevel@tonic-gate		else
774daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7757c478bd9Sstevel@tonic-gate		next
7767c478bd9Sstevel@tonic-gate	}
7777c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7787c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7797c478bd9Sstevel@tonic-gate		n1 = r[1]
7807c478bd9Sstevel@tonic-gate		n2 = r[2]
7817c478bd9Sstevel@tonic-gate		final = n2
7827c478bd9Sstevel@tonic-gate		d2 = 0;
7837c478bd9Sstevel@tonic-gate		if (n == 1) {
7847c478bd9Sstevel@tonic-gate			final = n1
785daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7867c478bd9Sstevel@tonic-gate		} else {
7877c478bd9Sstevel@tonic-gate			d2 = n2 - n1
788daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7897c478bd9Sstevel@tonic-gate		}
7907c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
7917c478bd9Sstevel@tonic-gate		n1 = r[1]
7927c478bd9Sstevel@tonic-gate		n2 = r[2]
7937c478bd9Sstevel@tonic-gate		if (m > 1) {
7947c478bd9Sstevel@tonic-gate			d1  = n2 - n1
7957c478bd9Sstevel@tonic-gate			if (d1 > d2) {
7967c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7977c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
7987c478bd9Sstevel@tonic-gate			}
7997c478bd9Sstevel@tonic-gate		}
8007c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8017c478bd9Sstevel@tonic-gate		next
8027c478bd9Sstevel@tonic-gate	}
8037c478bd9Sstevel@tonic-gate	}
804daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8057c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8067c478bd9Sstevel@tonic-gate
807daaffb31Sdp	#
808cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
809daaffb31Sdp	#
810cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8117c478bd9Sstevel@tonic-gate
812cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8137c478bd9Sstevel@tonic-gate
814daaffb31Sdp	#
815daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
816daaffb31Sdp	#
817daaffb31Sdp	print "$HTML<head>$STDHEAD"
818cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
819daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
820daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
821daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
822daaffb31Sdp	print "<table><tr valign=\"top\">"
823daaffb31Sdp	print "<td><pre>"
8247c478bd9Sstevel@tonic-gate
8257c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8267c478bd9Sstevel@tonic-gate
827daaffb31Sdp	print "</pre></td><td><pre>"
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8307c478bd9Sstevel@tonic-gate
831daaffb31Sdp	print "</pre></td>"
832daaffb31Sdp	print "</tr></table>"
833daaffb31Sdp	print "</body></html>"
8347c478bd9Sstevel@tonic-gate
835daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
836daaffb31Sdp	    "$COMMENT"
8377c478bd9Sstevel@tonic-gate}
8387c478bd9Sstevel@tonic-gate
8397c478bd9Sstevel@tonic-gate
840daaffb31Sdp#
841daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
842daaffb31Sdp#
843daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
844daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
845daaffb31Sdp# and then emit the main frame.  Content is placed into:
846daaffb31Sdp#
847daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
848daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
849daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
850daaffb31Sdp#
851daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
852daaffb31Sdp#
8537c478bd9Sstevel@tonic-gatefunction framed_sdiff
8547c478bd9Sstevel@tonic-gate{
8557c478bd9Sstevel@tonic-gate	typeset TNAME=$1
856daaffb31Sdp	typeset TPATH=$2
857daaffb31Sdp	typeset lhsfile=$3
858daaffb31Sdp	typeset rhsfile=$4
859daaffb31Sdp	typeset comments=$5
8607c478bd9Sstevel@tonic-gate	typeset RTOP
861daaffb31Sdp
8627c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
863daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
864daaffb31Sdp
865daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
866daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
867daaffb31Sdp
868daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8698b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8707c478bd9Sstevel@tonic-gate	    </head>
871daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
872cac38512Smjnelson	    <a name="0"></a>
873cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
874daaffb31Sdp	EOF
875daaffb31Sdp
876daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
877daaffb31Sdp
878daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
879daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
880daaffb31Sdp
881daaffb31Sdp	close='</body></html>'
882daaffb31Sdp
883daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
884daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
885daaffb31Sdp
886daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
887daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
888daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
889daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
890daaffb31Sdp	  <frameset rows="*,60">
891daaffb31Sdp	    <frameset cols="50%,50%">
892cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
893cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
894daaffb31Sdp	    </frameset>
8958b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
896cac38512Smjnelson	   marginheight="0" name="nav"></frame>
897daaffb31Sdp	  <noframes>
898daaffb31Sdp            <body id="SUNWwebrev">
899daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9007c478bd9Sstevel@tonic-gate	      and has the feature enabled.
901daaffb31Sdp            </body>
902daaffb31Sdp	  </noframes>
903daaffb31Sdp	  </frameset>
9047c478bd9Sstevel@tonic-gate	</html>
9057c478bd9Sstevel@tonic-gate	EOF
9067c478bd9Sstevel@tonic-gate}
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate
909daaffb31Sdp#
910daaffb31Sdp# fix_postscript
911daaffb31Sdp#
912daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
913daaffb31Sdp# 	- removing all extraneous headers/trailers
914daaffb31Sdp#	- making the page numbers right
915daaffb31Sdp#	- removing pages devoid of contents which confuse some
916daaffb31Sdp#	  postscript readers.
917daaffb31Sdp#
918daaffb31Sdp# From Casper.
919daaffb31Sdp#
920daaffb31Sdpfunction fix_postscript
9217c478bd9Sstevel@tonic-gate{
922daaffb31Sdp	infile=$1
9237c478bd9Sstevel@tonic-gate
924daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9257c478bd9Sstevel@tonic-gate
926daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
927daaffb31Sdp	print "%%Orientation: Landscape\n";
9287c478bd9Sstevel@tonic-gate
929daaffb31Sdp	$pno = 0;
930daaffb31Sdp	$doprint = 1;
931daaffb31Sdp
932daaffb31Sdp	$page = "";
933daaffb31Sdp
934daaffb31Sdp	while (<>) {
935daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
936daaffb31Sdp
937daaffb31Sdp		if (/^%%Page:/) {
938daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
939daaffb31Sdp				# Header or single page containing text
940daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
941daaffb31Sdp				print $page;
942daaffb31Sdp				$pno++;
943daaffb31Sdp			} else {
944daaffb31Sdp				# Empty page, skip it.
9457c478bd9Sstevel@tonic-gate			}
946daaffb31Sdp			$page = "";
947daaffb31Sdp			$doprint = 1;
9487c478bd9Sstevel@tonic-gate			next;
9497c478bd9Sstevel@tonic-gate		}
9507c478bd9Sstevel@tonic-gate
951daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
952daaffb31Sdp		# %%Page of the next
953daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
954daaffb31Sdp		$page .= $_ if ($doprint);
9557c478bd9Sstevel@tonic-gate	}
9567c478bd9Sstevel@tonic-gate
957daaffb31Sdp	if ($page =~ /\)S/) {
958daaffb31Sdp		print "%%Page: ? $pno\n";
959daaffb31Sdp		print $page;
960daaffb31Sdp	} else {
961daaffb31Sdp		$pno--;
962daaffb31Sdp	}
963daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
964daaffb31SdpEOF
965daaffb31Sdp
96614983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
967daaffb31Sdp}
968daaffb31Sdp
969daaffb31Sdp
970daaffb31Sdp#
971daaffb31Sdp# input_cmd | insert_anchors | output_cmd
972daaffb31Sdp#
9737c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
974daaffb31Sdp# anchors.  These are used to drive the frames version of the
9757c478bd9Sstevel@tonic-gate# sdiffs output.
9767c478bd9Sstevel@tonic-gate#
9777c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9787c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9797c478bd9Sstevel@tonic-gate#
980daaffb31Sdp# The script detects changed lines as any line that has a "<span
981daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
982daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
9837c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
9847c478bd9Sstevel@tonic-gate# deleted.
9857c478bd9Sstevel@tonic-gate#
986daaffb31Sdpfunction insert_anchors
987daaffb31Sdp{
988cdf0c1d5Smjnelson	$AWK '
9897c478bd9Sstevel@tonic-gate	function ia() {
990daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
9917c478bd9Sstevel@tonic-gate	}
992daaffb31Sdp
9937c478bd9Sstevel@tonic-gate	BEGIN {
994daaffb31Sdp		anc=1;
9957c478bd9Sstevel@tonic-gate		inblock=1;
996daaffb31Sdp		printf "<pre>\n";
9977c478bd9Sstevel@tonic-gate	}
998daaffb31Sdp	NF == 0 || /^<span class=/ {
9997c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10007c478bd9Sstevel@tonic-gate			ia();
10017c478bd9Sstevel@tonic-gate			inblock=1;
10027c478bd9Sstevel@tonic-gate		}
10037c478bd9Sstevel@tonic-gate		print;
10047c478bd9Sstevel@tonic-gate		next;
10057c478bd9Sstevel@tonic-gate	}
10067c478bd9Sstevel@tonic-gate	{
10077c478bd9Sstevel@tonic-gate		inblock=0;
10087c478bd9Sstevel@tonic-gate		print;
10097c478bd9Sstevel@tonic-gate	}
10107c478bd9Sstevel@tonic-gate	END {
10117c478bd9Sstevel@tonic-gate		ia();
1012daaffb31Sdp
1013daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1014daaffb31Sdp		printf "--- EOF ---</b>"
10157c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1016daaffb31Sdp		printf "</pre>"
1017daaffb31Sdp		printf "<form name=\"eof\">";
1018cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1019cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1020daaffb31Sdp		printf "</form>";
10217c478bd9Sstevel@tonic-gate	}
10227c478bd9Sstevel@tonic-gate	' $1
10237c478bd9Sstevel@tonic-gate}
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate
1026daaffb31Sdp#
1027daaffb31Sdp# relative_dir
1028daaffb31Sdp#
1029daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1030daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1031daaffb31Sdp# this function would print "../../../../".
1032daaffb31Sdp#
1033daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1034daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1035daaffb31Sdp# is not relocatable.
1036daaffb31Sdp#
1037daaffb31Sdpfunction relative_dir
10387c478bd9Sstevel@tonic-gate{
1039daaffb31Sdp        typeset cur="${1##$2?(/)}"
10408b3b7b16SMark J. Nelson
10418b3b7b16SMark J. Nelson        #
10428b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
10438b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
10448b3b7b16SMark J. Nelson        #
1045*0fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1046daaffb31Sdp                # Should never happen.
104714983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1048daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1049daaffb31Sdp                print -u2 "will not be relocatable!"
1050daaffb31Sdp                print $2
1051daaffb31Sdp                return
1052daaffb31Sdp        fi
1053daaffb31Sdp
10548b3b7b16SMark J. Nelson	#
10558b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
10568b3b7b16SMark J. Nelson	#
10578b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
10588b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
10598b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
10608b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
10618b3b7b16SMark J. Nelson	#    the end of a relative path.
10628b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
10638b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
10648b3b7b16SMark J. Nelson	#    level of relative separation.
10658b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
10668b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
10678b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
10688b3b7b16SMark J. Nelson	#
1069*0fd2682eSMark J. Nelson	print $cur | $SED -e '{
10708b3b7b16SMark J. Nelson		s:^\./*::
10718b3b7b16SMark J. Nelson		s:/$::
10728b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
1073*0fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
1074*0fd2682eSMark J. Nelson	}'
10757c478bd9Sstevel@tonic-gate}
10767c478bd9Sstevel@tonic-gate
1077daaffb31Sdp#
1078daaffb31Sdp# frame_nav_js
1079daaffb31Sdp#
1080daaffb31Sdp# Emit javascript for frame navigation
1081daaffb31Sdp#
1082daaffb31Sdpfunction frame_nav_js
10837c478bd9Sstevel@tonic-gate{
10847c478bd9Sstevel@tonic-gatecat << \EOF
10857c478bd9Sstevel@tonic-gatevar myInt;
10867c478bd9Sstevel@tonic-gatevar scrolling=0;
1087daaffb31Sdpvar sfactor = 3;
10887c478bd9Sstevel@tonic-gatevar scount=10;
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gatefunction scrollByPix() {
10917c478bd9Sstevel@tonic-gate	if (scount<=0) {
10927c478bd9Sstevel@tonic-gate		sfactor*=1.2;
10937c478bd9Sstevel@tonic-gate		scount=10;
10947c478bd9Sstevel@tonic-gate	}
10957c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
10967c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
10977c478bd9Sstevel@tonic-gate	scount--;
10987c478bd9Sstevel@tonic-gate}
10997c478bd9Sstevel@tonic-gate
1100daaffb31Sdpfunction scrollToAnc(num) {
1101daaffb31Sdp
1102daaffb31Sdp	// Update the value of the anchor in the form which we use as
1103daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1104daaffb31Sdp	// correcting for overflow and underflow of the value and return
1105daaffb31Sdp	// us the new value.
1106daaffb31Sdp	num = setAncValue(num);
1107daaffb31Sdp
1108daaffb31Sdp	// Set location and scroll back a little to expose previous
1109daaffb31Sdp	// lines.
1110daaffb31Sdp	//
1111daaffb31Sdp	// Note that this could be improved: it is possible although
1112daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1113daaffb31Sdp	// scroll to that location directly.
1114daaffb31Sdp	//
11157c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11167c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1117daaffb31Sdp
11187c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11197c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11207c478bd9Sstevel@tonic-gate}
11217c478bd9Sstevel@tonic-gate
1122daaffb31Sdpfunction getAncValue()
1123daaffb31Sdp{
1124daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1125daaffb31Sdp}
1126daaffb31Sdp
1127daaffb31Sdpfunction setAncValue(val)
1128daaffb31Sdp{
1129daaffb31Sdp	if (val <= 0) {
1130daaffb31Sdp		val = 0;
1131daaffb31Sdp		parent.nav.document.diff.real.value = val;
1132daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1133daaffb31Sdp		return (val);
1134daaffb31Sdp	}
1135daaffb31Sdp
1136daaffb31Sdp	//
1137daaffb31Sdp	// The way we compute the max anchor value is to stash it
1138daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1139daaffb31Sdp	// on each side, so we pluck from the left.
1140daaffb31Sdp	//
1141daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1142daaffb31Sdp	if (val < maxval) {
1143daaffb31Sdp		parent.nav.document.diff.real.value = val;
1144daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1145daaffb31Sdp		return (val);
1146daaffb31Sdp	}
1147daaffb31Sdp
1148daaffb31Sdp	// this must be: val >= maxval
1149daaffb31Sdp	val = maxval;
1150daaffb31Sdp	parent.nav.document.diff.real.value = val;
1151daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1152daaffb31Sdp	return (val);
1153daaffb31Sdp}
1154daaffb31Sdp
11557c478bd9Sstevel@tonic-gatefunction stopScroll() {
11567c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11577c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11587c478bd9Sstevel@tonic-gate		scrolling=0;
11597c478bd9Sstevel@tonic-gate	}
11607c478bd9Sstevel@tonic-gate}
11617c478bd9Sstevel@tonic-gate
11627c478bd9Sstevel@tonic-gatefunction startScroll() {
11637c478bd9Sstevel@tonic-gate	stopScroll();
11647c478bd9Sstevel@tonic-gate	scrolling=1;
11657c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11667c478bd9Sstevel@tonic-gate}
11677c478bd9Sstevel@tonic-gate
11687c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1169daaffb31Sdp
11707c478bd9Sstevel@tonic-gate	switch (b) {
11717c478bd9Sstevel@tonic-gate	    case 1 :
1172daaffb31Sdp		scrollToAnc(-1);
11737c478bd9Sstevel@tonic-gate		break;
11747c478bd9Sstevel@tonic-gate	    case 2 :
1175daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11767c478bd9Sstevel@tonic-gate		break;
11777c478bd9Sstevel@tonic-gate	    case 3 :
11787c478bd9Sstevel@tonic-gate		sfactor=-3;
11797c478bd9Sstevel@tonic-gate		startScroll();
11807c478bd9Sstevel@tonic-gate		break;
11817c478bd9Sstevel@tonic-gate	    case 4 :
11827c478bd9Sstevel@tonic-gate		sfactor=3;
11837c478bd9Sstevel@tonic-gate		startScroll();
11847c478bd9Sstevel@tonic-gate		break;
11857c478bd9Sstevel@tonic-gate	    case 5 :
1186daaffb31Sdp		scrollToAnc(getAncValue() + 1);
11877c478bd9Sstevel@tonic-gate		break;
11887c478bd9Sstevel@tonic-gate	    case 6 :
1189daaffb31Sdp		scrollToAnc(999999);
11907c478bd9Sstevel@tonic-gate		break;
11917c478bd9Sstevel@tonic-gate	}
11927c478bd9Sstevel@tonic-gate}
11937c478bd9Sstevel@tonic-gate
11947c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
11957c478bd9Sstevel@tonic-gate	stopScroll();
11967c478bd9Sstevel@tonic-gate}
11977c478bd9Sstevel@tonic-gate
1198daaffb31Sdpfunction keypress(ev) {
1199daaffb31Sdp	var keynum;
1200daaffb31Sdp	var keychar;
1201daaffb31Sdp
1202daaffb31Sdp	if (window.event) { // IE
1203daaffb31Sdp		keynum = ev.keyCode;
1204daaffb31Sdp	} else if (ev.which) { // non-IE
1205daaffb31Sdp		keynum = ev.which;
1206daaffb31Sdp	}
1207daaffb31Sdp
1208daaffb31Sdp	keychar = String.fromCharCode(keynum);
1209daaffb31Sdp
1210daaffb31Sdp	if (keychar == "k") {
1211daaffb31Sdp		handlePress(2);
1212daaffb31Sdp		return (0);
1213daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1214daaffb31Sdp		handlePress(5);
1215daaffb31Sdp		return (0);
1216daaffb31Sdp	}
1217daaffb31Sdp	return (1);
1218daaffb31Sdp}
1219daaffb31Sdp
12207c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1221daaffb31Sdp	val = parent.nav.document.diff.display.value;
1222daaffb31Sdp	if (val == "EOF") {
1223daaffb31Sdp		scrollToAnc(999999);
1224daaffb31Sdp		return;
1225daaffb31Sdp	}
1226daaffb31Sdp
1227daaffb31Sdp	if (val == "BOF") {
1228daaffb31Sdp		scrollToAnc(0);
1229daaffb31Sdp		return;
1230daaffb31Sdp	}
1231daaffb31Sdp
1232daaffb31Sdp        i=parseInt(val);
12337c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1234daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12357c478bd9Sstevel@tonic-gate        } else {
1236daaffb31Sdp                scrollToAnc(i);
12377c478bd9Sstevel@tonic-gate        }
12387c478bd9Sstevel@tonic-gate        return false;
12397c478bd9Sstevel@tonic-gate}
12407c478bd9Sstevel@tonic-gate
1241daaffb31SdpEOF
1242daaffb31Sdp}
1243daaffb31Sdp
1244daaffb31Sdp#
1245daaffb31Sdp# frame_navigation
1246daaffb31Sdp#
1247daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1248daaffb31Sdp#
1249daaffb31Sdpfunction frame_navigation
1250daaffb31Sdp{
1251daaffb31Sdp	print "$HTML<head>$STDHEAD"
1252daaffb31Sdp
1253daaffb31Sdp	cat << \EOF
1254daaffb31Sdp<title>Anchor Navigation</title>
1255daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1256daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1257daaffb31Sdp
1258daaffb31Sdp<style type="text/css">
1259daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1260daaffb31Sdp		    background-color: #eee; text-align: center;
1261daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1262daaffb31Sdp    div.button a { font-weight: bold; color: black }
1263daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1264daaffb31Sdp</style>
1265daaffb31SdpEOF
1266daaffb31Sdp
1267cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1268daaffb31Sdp
1269daaffb31Sdp	cat << \EOF
12707c478bd9Sstevel@tonic-gate</head>
1271daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1272daaffb31Sdp	onkeypress="keypress(event);">
12737c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12747c478bd9Sstevel@tonic-gate      <center>
1275cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12767c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12777c478bd9Sstevel@tonic-gate      </center>
12787c478bd9Sstevel@tonic-gate    </noscript>
12797c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1280daaffb31Sdp	<tr>
1281daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1282daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1283daaffb31Sdp          at right</td>
1284daaffb31Sdp	  <td align="center" valign="top" width="50%">
12857c478bd9Sstevel@tonic-gate	    <div class="button">
1286daaffb31Sdp	      <table border="0" align="center">
1287daaffb31Sdp                  <tr>
1288daaffb31Sdp		    <td>
12897c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
12907c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
12917c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
12927c478bd9Sstevel@tonic-gate			 onClick="return false;"
12937c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1294daaffb31Sdp		    <td>
12957c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
12967c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
12977c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
12987c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1299daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1300daaffb31Sdp		    <td>
13017c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13027c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13037c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13047c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13057c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13067c478bd9Sstevel@tonic-gate		    </td></tr>
1307daaffb31Sdp
13087c478bd9Sstevel@tonic-gate		  <tr>
1309daaffb31Sdp		    <td>
13107c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13117c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13127c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13137c478bd9Sstevel@tonic-gate			 onClick="return false;"
13147c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1315daaffb31Sdp		    <td>
13167c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13177c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13187c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13197c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1320daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1321daaffb31Sdp		    <td>
13227c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13237c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13247c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13257c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13267c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1327daaffb31Sdp		  </tr>
1328daaffb31Sdp              </table>
1329daaffb31Sdp	    </div>
1330daaffb31Sdp	  </td>
13317c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1332daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1333cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1334cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13357c478bd9Sstevel@tonic-gate	    </form>
13367c478bd9Sstevel@tonic-gate	  </th>
1337daaffb31Sdp	</tr>
13387c478bd9Sstevel@tonic-gate    </table>
13397c478bd9Sstevel@tonic-gate  </body>
13407c478bd9Sstevel@tonic-gate</html>
13417c478bd9Sstevel@tonic-gateEOF
13427c478bd9Sstevel@tonic-gate}
13437c478bd9Sstevel@tonic-gate
13447c478bd9Sstevel@tonic-gate
1345daaffb31Sdp
1346daaffb31Sdp#
1347daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1348daaffb31Sdp#
1349daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1350daaffb31Sdp# context or unified diffs.
1351daaffb31Sdp#
13527c478bd9Sstevel@tonic-gatediff_to_html()
13537c478bd9Sstevel@tonic-gate{
13547c478bd9Sstevel@tonic-gate	TNAME=$1
1355daaffb31Sdp	TPATH=$2
1356daaffb31Sdp	DIFFTYPE=$3
1357daaffb31Sdp	COMMENT=$4
1358daaffb31Sdp
1359daaffb31Sdp	print "$HTML<head>$STDHEAD"
1360daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1361daaffb31Sdp
1362daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1363daaffb31Sdp		print "$UDIFFCSS"
1364daaffb31Sdp	fi
1365daaffb31Sdp
1366daaffb31Sdp	cat <<-EOF
1367daaffb31Sdp	</head>
1368daaffb31Sdp	<body id="SUNWwebrev">
1369daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1370daaffb31Sdp	<pre>$COMMENT</pre>
1371daaffb31Sdp        <pre>
1372daaffb31Sdp	EOF
13737c478bd9Sstevel@tonic-gate
1374cdf0c1d5Smjnelson	html_quote | $AWK '
1375daaffb31Sdp	/^--- new/	{ next }
1376daaffb31Sdp	/^\+\+\+ new/	{ next }
1377daaffb31Sdp	/^--- old/	{ next }
1378daaffb31Sdp	/^\*\*\* old/	{ next }
1379daaffb31Sdp	/^\*\*\*\*/	{ next }
13807c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1381cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1382daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1383daaffb31Sdp			  next}
1384daaffb31Sdp
1385cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1386daaffb31Sdp			  next}
1387daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1388daaffb31Sdp			  next}
1389daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1390daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1391daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1392daaffb31Sdp			{printf "%s\n", $0; next}
13937c478bd9Sstevel@tonic-gate	'
1394daaffb31Sdp
1395daaffb31Sdp	print "</pre></body></html>\n"
13967c478bd9Sstevel@tonic-gate}
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate
1399daaffb31Sdp#
1400daaffb31Sdp# source_to_html { new | old } <filename>
1401daaffb31Sdp#
1402daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1403daaffb31Sdp#
14047c478bd9Sstevel@tonic-gatesource_to_html()
14057c478bd9Sstevel@tonic-gate{
14067c478bd9Sstevel@tonic-gate	WHICH=$1
14077c478bd9Sstevel@tonic-gate	TNAME=$2
14087c478bd9Sstevel@tonic-gate
1409daaffb31Sdp	print "$HTML<head>$STDHEAD"
1410cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1411daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1412daaffb31Sdp	print "<pre>"
1413cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1414daaffb31Sdp	print "</pre></body></html>"
14157c478bd9Sstevel@tonic-gate}
14167c478bd9Sstevel@tonic-gate
1417daaffb31Sdp#
1418cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1419daaffb31Sdp#
1420daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1421daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1422daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1423daaffb31Sdp# delta in that list (the first delta unique to the child).
14247c478bd9Sstevel@tonic-gate#
14257c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1426daaffb31Sdp#
1427daaffb31Sdpcomments_from_teamware()
14287c478bd9Sstevel@tonic-gate{
1429daaffb31Sdp	fmt=$1
1430daaffb31Sdp	pfile=$PWS/$2
1431daaffb31Sdp	cfile=$CWS/$3
14327c478bd9Sstevel@tonic-gate
1433cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1434cdf0c1d5Smjnelson		pfile=$RWS/$2
1435cdf0c1d5Smjnelson	fi
1436cdf0c1d5Smjnelson
1437daaffb31Sdp	if [[ -f $pfile ]]; then
1438cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14397c478bd9Sstevel@tonic-gate	else
14407c478bd9Sstevel@tonic-gate		psid=1.1
14417c478bd9Sstevel@tonic-gate	fi
14427c478bd9Sstevel@tonic-gate
1443cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14447c478bd9Sstevel@tonic-gate	N=${#sids[@]}
14457c478bd9Sstevel@tonic-gate
1446daaffb31Sdp	nawkprg='
1447daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1448daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1449daaffb31Sdp		NF == 0u	{ continue }
1450daaffb31Sdp		{if (p==0) continue; print $0 }'
1451daaffb31Sdp
14527c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
14537c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14547c478bd9Sstevel@tonic-gate
1455daaffb31Sdp		if [[ $fmt == "text" ]]; then
1456cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1457cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1458daaffb31Sdp			return
1459daaffb31Sdp		fi
1460daaffb31Sdp
1461cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1462*0fd2682eSMark J. Nelson		    html_quote | its2url | $AWK "$nawkprg"
14637c478bd9Sstevel@tonic-gate	fi
14647c478bd9Sstevel@tonic-gate}
14657c478bd9Sstevel@tonic-gate
1466daaffb31Sdp#
1467cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1468daaffb31Sdp#
1469cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1470cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1471cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1472cdf0c1d5Smjnelson# are turned into URLs.
1473cdf0c1d5Smjnelson#
1474cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1475daaffb31Sdp#
1476daaffb31Sdpcomments_from_wx()
14777c478bd9Sstevel@tonic-gate{
1478daaffb31Sdp	typeset fmt=$1
1479daaffb31Sdp	typeset p=$2
14807c478bd9Sstevel@tonic-gate
1481cdf0c1d5Smjnelson	comm=`$AWK '
1482daaffb31Sdp	$1 == "'$p'" {
14837c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
14847c478bd9Sstevel@tonic-gate		getline
14857c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
14867c478bd9Sstevel@tonic-gate		exit
1487daaffb31Sdp	}' < $wxfile`
1488daaffb31Sdp
1489cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1490cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1491cdf0c1d5Smjnelson	fi
1492cdf0c1d5Smjnelson
1493daaffb31Sdp	if [[ $fmt == "text" ]]; then
1494cdf0c1d5Smjnelson		print -- "$comm"
1495daaffb31Sdp		return
1496daaffb31Sdp	fi
1497daaffb31Sdp
1498*0fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1499cdf0c1d5Smjnelson
15007c478bd9Sstevel@tonic-gate}
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate#
1503daaffb31Sdp# getcomments {text|html} filepath parentpath
1504daaffb31Sdp#
1505daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1506daaffb31Sdp#
1507daaffb31Sdpgetcomments()
1508daaffb31Sdp{
1509daaffb31Sdp	typeset fmt=$1
1510daaffb31Sdp	typeset p=$2
1511daaffb31Sdp	typeset pp=$3
15127c478bd9Sstevel@tonic-gate
15133df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15143df69ef3SDarren Moffat		return
15153df69ef3SDarren Moffat	fi
1516cdf0c1d5Smjnelson	#
1517cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1518cdf0c1d5Smjnelson	# will be used there, too
1519cdf0c1d5Smjnelson	#
1520daaffb31Sdp	if [[ -n $wxfile ]]; then
1521daaffb31Sdp		comments_from_wx $fmt $p
1522daaffb31Sdp	else
1523daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1524daaffb31Sdp			comments_from_teamware $fmt $pp $p
1525daaffb31Sdp		fi
1526daaffb31Sdp	fi
1527daaffb31Sdp}
1528daaffb31Sdp
1529daaffb31Sdp#
1530daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1531daaffb31Sdp#
1532daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1533daaffb31Sdp#
1534daaffb31Sdpfunction printCI
1535daaffb31Sdp{
1536daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1537daaffb31Sdp	typeset str
1538daaffb31Sdp	if (( tot == 1 )); then
1539daaffb31Sdp		str="line"
1540daaffb31Sdp	else
1541daaffb31Sdp		str="lines"
1542daaffb31Sdp	fi
1543daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1544daaffb31Sdp	    $tot $str $ins $del $mod $unc
1545daaffb31Sdp}
1546daaffb31Sdp
1547daaffb31Sdp
1548daaffb31Sdp#
1549daaffb31Sdp# difflines <oldfile> <newfile>
1550daaffb31Sdp#
1551daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1552daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1553daaffb31Sdp#
15547c478bd9Sstevel@tonic-gatefunction difflines
15557c478bd9Sstevel@tonic-gate{
1556daaffb31Sdp	integer tot mod del ins unc err
15577c478bd9Sstevel@tonic-gate	typeset filename
15587c478bd9Sstevel@tonic-gate
1559cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1560daaffb31Sdp	# Change range of lines: N,Nc
15617c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15627c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15637c478bd9Sstevel@tonic-gate		if (n != 2) {
15647c478bd9Sstevel@tonic-gate		    error=2
15657c478bd9Sstevel@tonic-gate		    exit;
15667c478bd9Sstevel@tonic-gate		}
1567daaffb31Sdp		#
1568daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1569daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1570daaffb31Sdp		#
15717c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1572daaffb31Sdp
1573daaffb31Sdp		#
1574daaffb31Sdp		# Now count replacement lines: each represents a change instead
1575daaffb31Sdp		# of a delete, so increment c and decrement r.
1576daaffb31Sdp		#
15777c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15787c478bd9Sstevel@tonic-gate			c++;
15797c478bd9Sstevel@tonic-gate			r--;
15807c478bd9Sstevel@tonic-gate		}
1581daaffb31Sdp		#
1582daaffb31Sdp		# If there were more replacement lines than original lines,
1583daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1584daaffb31Sdp		# but there are r changes that should be counted as adds, and
1585daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1586daaffb31Sdp		#
15877c478bd9Sstevel@tonic-gate		if (r < 0) {
15887c478bd9Sstevel@tonic-gate			a-=r;
15897c478bd9Sstevel@tonic-gate			c+=r;
15907c478bd9Sstevel@tonic-gate		}
1591daaffb31Sdp
1592daaffb31Sdp		#
1593daaffb31Sdp		# If there were more original lines than replacement lines, then
1594daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1595daaffb31Sdp		#
15967c478bd9Sstevel@tonic-gate		if (r > 0) {
15977c478bd9Sstevel@tonic-gate			d+=r;
15987c478bd9Sstevel@tonic-gate		}
15997c478bd9Sstevel@tonic-gate		next;
16007c478bd9Sstevel@tonic-gate	}
16017c478bd9Sstevel@tonic-gate
1602daaffb31Sdp	# Change lines: Nc
16037c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1604daaffb31Sdp		# The first line is a replacement; any more are additions.
16057c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16067c478bd9Sstevel@tonic-gate			c++;
16077c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16087c478bd9Sstevel@tonic-gate		}
16097c478bd9Sstevel@tonic-gate		next;
16107c478bd9Sstevel@tonic-gate	}
16117c478bd9Sstevel@tonic-gate
1612daaffb31Sdp	# Add lines: both Na and N,Na
16137c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16147c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16157c478bd9Sstevel@tonic-gate		next;
16167c478bd9Sstevel@tonic-gate	}
16177c478bd9Sstevel@tonic-gate
1618daaffb31Sdp	# Delete range of lines: N,Nd
16197c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16207c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16217c478bd9Sstevel@tonic-gate		if (n != 2) {
16227c478bd9Sstevel@tonic-gate			error=2
16237c478bd9Sstevel@tonic-gate			exit;
16247c478bd9Sstevel@tonic-gate		}
1625daaffb31Sdp		#
1626daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1627daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1628daaffb31Sdp		#
16297c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16307c478bd9Sstevel@tonic-gate		d+=r;
16317c478bd9Sstevel@tonic-gate		next;
16327c478bd9Sstevel@tonic-gate	}
16337c478bd9Sstevel@tonic-gate
1634daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16357c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16367c478bd9Sstevel@tonic-gate
1637daaffb31Sdp	# Should not get here!
16387c478bd9Sstevel@tonic-gate	{
16397c478bd9Sstevel@tonic-gate		error=1;
16407c478bd9Sstevel@tonic-gate		exit;
16417c478bd9Sstevel@tonic-gate	}
16427c478bd9Sstevel@tonic-gate
1643daaffb31Sdp	# Finish off - print results
16447c478bd9Sstevel@tonic-gate	END {
1645daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16467c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16477c478bd9Sstevel@tonic-gate	}' )
16487c478bd9Sstevel@tonic-gate
1649cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16507c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1651daaffb31Sdp		print "Unexpected Error occurred reading" \
1652daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1653daaffb31Sdp		return
1654daaffb31Sdp	fi
1655daaffb31Sdp
16567c478bd9Sstevel@tonic-gate	# Accumulate totals
16577c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1658daaffb31Sdp	(( TMOD += mod ))
16597c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16607c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16617c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1662cdf0c1d5Smjnelson	unc=`wc -l < $1`
16637c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1664daaffb31Sdp		(( unc -= del + mod ))
16657c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16667c478bd9Sstevel@tonic-gate	fi
16677c478bd9Sstevel@tonic-gate	# print summary
1668daaffb31Sdp	print "<span class=\"lineschanged\">"
1669daaffb31Sdp	printCI $tot $ins $del $mod $unc
1670daaffb31Sdp	print "</span>"
16717c478bd9Sstevel@tonic-gate}
16727c478bd9Sstevel@tonic-gate
1673daaffb31Sdp
16747c478bd9Sstevel@tonic-gate#
1675daaffb31Sdp# flist_from_wx
1676daaffb31Sdp#
1677daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1678daaffb31Sdp# Sets the global 'wxfile' variable.
1679daaffb31Sdp#
1680daaffb31Sdpfunction flist_from_wx
16817c478bd9Sstevel@tonic-gate{
1682daaffb31Sdp	typeset argfile=$1
1683daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1684daaffb31Sdp		#
1685daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1686daaffb31Sdp		# because the webrev does a "cd" later on.
1687daaffb31Sdp		#
1688daaffb31Sdp		wxfile=$PWD/$argfile
16897c478bd9Sstevel@tonic-gate	else
1690daaffb31Sdp		wxfile=$argfile
16917c478bd9Sstevel@tonic-gate	fi
16927c478bd9Sstevel@tonic-gate
1693cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
16947c478bd9Sstevel@tonic-gate	  while (getline) {
16957c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
16967c478bd9Sstevel@tonic-gate		if (c > 0) print
16977c478bd9Sstevel@tonic-gate	  }
1698daaffb31Sdp	}' $wxfile > $FLIST
16997c478bd9Sstevel@tonic-gate
1700daaffb31Sdp	print " Done."
1701daaffb31Sdp}
17027c478bd9Sstevel@tonic-gate
1703daaffb31Sdp#
1704daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1705daaffb31Sdp#
1706daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1707daaffb31Sdp# names may come from the "update/create" messages and others from the
1708daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1709daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1710daaffb31Sdp# -n as well, but remove them if they are already defined.
1711daaffb31Sdp#
1712daaffb31Sdpfunction flist_from_teamware
1713daaffb31Sdp{
1714cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1715daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1716daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1717daaffb31Sdp			    "valid teamware workspace"
17187c478bd9Sstevel@tonic-gate			exit 1
17197c478bd9Sstevel@tonic-gate		fi
1720daaffb31Sdp		parent_args="-p $codemgr_parent"
17217c478bd9Sstevel@tonic-gate	fi
17227c478bd9Sstevel@tonic-gate
1723daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17247c478bd9Sstevel@tonic-gate
1725daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1726cdf0c1d5Smjnelson	    $AWK '
1727daaffb31Sdp		/^update:|^create:/	{print $2}
1728daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1729daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1730daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1731daaffb31Sdp		NF == 0			{p=0 ; continue}
1732daaffb31Sdp		/^rename/		{old=$3}
1733daaffb31Sdp		$1 == "to:"		{print $2, old}
1734daaffb31Sdp		/^"/			{continue}
1735daaffb31Sdp		p == 1			{print $1}' |
1736daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17377c478bd9Sstevel@tonic-gate
1738daaffb31Sdp	print " Done."
1739daaffb31Sdp}
1740daaffb31Sdp
1741cdf0c1d5Smjnelson#
1742cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1743cdf0c1d5Smjnelson#
1744cdf0c1d5Smjnelsonfunction hg_active_wxfile
1745cdf0c1d5Smjnelson{
1746cdf0c1d5Smjnelson	typeset child=$1
1747cdf0c1d5Smjnelson	typeset parent=$2
1748cdf0c1d5Smjnelson
1749cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17509a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1751cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1752cdf0c1d5Smjnelson}
1753cdf0c1d5Smjnelson
1754cdf0c1d5Smjnelson#
1755cdf0c1d5Smjnelson# flist_from_mercurial
1756cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1757cdf0c1d5Smjnelson# flist_from_wx
1758cdf0c1d5Smjnelson#
1759cdf0c1d5Smjnelsonfunction flist_from_mercurial
1760cdf0c1d5Smjnelson{
1761cdf0c1d5Smjnelson	typeset child=$1
1762cdf0c1d5Smjnelson	typeset parent=$2
1763cdf0c1d5Smjnelson
1764cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1765cdf0c1d5Smjnelson
1766cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1767cdf0c1d5Smjnelson		print		# Blank line for the \c above
1768cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1769cdf0c1d5Smjnelson		exit 1
1770cdf0c1d5Smjnelson	fi
1771cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1772cdf0c1d5Smjnelson
1773cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1774cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1775cdf0c1d5Smjnelson}
1776cdf0c1d5Smjnelson
1777cdf0c1d5Smjnelson#
1778cdf0c1d5Smjnelson# flist_from_subversion
1779cdf0c1d5Smjnelson#
1780cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1781cdf0c1d5Smjnelson#
1782cdf0c1d5Smjnelsonfunction flist_from_subversion
1783cdf0c1d5Smjnelson{
1784cdf0c1d5Smjnelson	CWS=$1
1785cdf0c1d5Smjnelson	OLDPWD=$2
1786cdf0c1d5Smjnelson
1787cdf0c1d5Smjnelson	cd $CWS
1788cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1789cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1790cdf0c1d5Smjnelson	print -u2 " Done."
1791cdf0c1d5Smjnelson	cd $OLDPWD
1792cdf0c1d5Smjnelson}
1793cdf0c1d5Smjnelson
1794daaffb31Sdpfunction env_from_flist
1795daaffb31Sdp{
1796daaffb31Sdp	[[ -r $FLIST ]] || return
1797daaffb31Sdp
1798daaffb31Sdp	#
1799daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1800daaffb31Sdp	# list.  Then copy those into our local versions of those
1801daaffb31Sdp	# variables if they have not been set already.
1802daaffb31Sdp	#
1803b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18047c478bd9Sstevel@tonic-gate
1805cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1806cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1807cdf0c1d5Smjnelson		export CODEMGR_WS
1808cdf0c1d5Smjnelson	fi
18097c478bd9Sstevel@tonic-gate
1810daaffb31Sdp	#
1811daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1812daaffb31Sdp	#
1813cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1814daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1815cdf0c1d5Smjnelson		export CODEMGR_PARENT
1816daaffb31Sdp	fi
1817daaffb31Sdp}
1818daaffb31Sdp
181914983201Sdpfunction look_for_prog
182014983201Sdp{
182114983201Sdp	typeset path
182214983201Sdp	typeset ppath
182314983201Sdp	typeset progname=$1
182414983201Sdp
182514983201Sdp	ppath=$PATH
182614983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
182714983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1828cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
182914983201Sdp
183014983201Sdp	PATH=$ppath prog=`whence $progname`
183114983201Sdp	if [[ -n $prog ]]; then
183214983201Sdp		print $prog
183314983201Sdp	fi
183414983201Sdp}
183514983201Sdp
1836cdf0c1d5Smjnelsonfunction get_file_mode
1837cdf0c1d5Smjnelson{
1838cdf0c1d5Smjnelson	$PERL -e '
1839cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1840cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1841cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1842cdf0c1d5Smjnelson			exit 0;
1843cdf0c1d5Smjnelson		} else {
1844cdf0c1d5Smjnelson			exit 1;
1845cdf0c1d5Smjnelson		}
1846cdf0c1d5Smjnelson	    ' $1
1847cdf0c1d5Smjnelson}
1848cdf0c1d5Smjnelson
1849cdf0c1d5Smjnelsonfunction build_old_new_teamware
1850cdf0c1d5Smjnelson{
1851cdf0c1d5Smjnelson	typeset olddir="$1"
1852cdf0c1d5Smjnelson	typeset newdir="$2"
1853cdf0c1d5Smjnelson
1854cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1855cdf0c1d5Smjnelson	# get a readonly copy.
1856cdf0c1d5Smjnelson
1857cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1858cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1859cdf0c1d5Smjnelson	fi
1860cdf0c1d5Smjnelson
1861cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1862cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1863cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1864cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1865cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1866cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1867cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1868cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1869cdf0c1d5Smjnelson	# permissions that would result after check in.
1870cdf0c1d5Smjnelson
1871cdf0c1d5Smjnelson	#
1872cdf0c1d5Smjnelson	# Snag new version of file.
1873cdf0c1d5Smjnelson	#
1874cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1875cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1876cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1877cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1878cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1879cdf0c1d5Smjnelson	fi
1880cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1881cdf0c1d5Smjnelson
1882cdf0c1d5Smjnelson	#
1883cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1884cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1885cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1886cdf0c1d5Smjnelson	#
1887cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1888cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1889cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1890cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1891cdf0c1d5Smjnelson		# the old file.
1892cdf0c1d5Smjnelson
1893cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1894cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1895cdf0c1d5Smjnelson	else
1896cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1897cdf0c1d5Smjnelson			real_parent=$PWS
1898cdf0c1d5Smjnelson		else
1899cdf0c1d5Smjnelson			real_parent=$RWS
1900cdf0c1d5Smjnelson		fi
1901cdf0c1d5Smjnelson
1902cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1903cdf0c1d5Smjnelson
1904cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1905cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1906cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1907cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1908cdf0c1d5Smjnelson			else
1909cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1910cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1911cdf0c1d5Smjnelson			fi
1912cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1913cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1914cdf0c1d5Smjnelson		fi
1915cdf0c1d5Smjnelson	fi
1916cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1917cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1918cdf0c1d5Smjnelson	fi
1919cdf0c1d5Smjnelson}
1920cdf0c1d5Smjnelson
1921cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1922cdf0c1d5Smjnelson{
1923cdf0c1d5Smjnelson	typeset olddir="$1"
1924cdf0c1d5Smjnelson	typeset newdir="$2"
1925cdf0c1d5Smjnelson	typeset old_mode=
1926cdf0c1d5Smjnelson	typeset new_mode=
1927cdf0c1d5Smjnelson	typeset file
1928cdf0c1d5Smjnelson
1929cdf0c1d5Smjnelson	#
1930cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1931cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1932cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1933cdf0c1d5Smjnelson	#
1934cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1935cdf0c1d5Smjnelson		file="$PF"
1936cdf0c1d5Smjnelson	else
1937cdf0c1d5Smjnelson		file="$PDIR/$PF"
1938cdf0c1d5Smjnelson	fi
1939b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
1940cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1941b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1942cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1943cdf0c1d5Smjnelson
1944cdf0c1d5Smjnelson	#
1945cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1946cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1947cdf0c1d5Smjnelson	#
1948cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1949cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1950cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1951cdf0c1d5Smjnelson			new_mode=755
1952cdf0c1d5Smjnelson		else
1953cdf0c1d5Smjnelson			new_mode=644
1954cdf0c1d5Smjnelson		fi
1955cdf0c1d5Smjnelson	fi
1956cdf0c1d5Smjnelson
1957cdf0c1d5Smjnelson	#
1958cdf0c1d5Smjnelson	# new version of the file.
1959cdf0c1d5Smjnelson	#
1960cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1961cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1962cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1963cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1964cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1965cdf0c1d5Smjnelson		else
1966cdf0c1d5Smjnelson			# should never happen
1967cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1968cdf0c1d5Smjnelson		fi
1969cdf0c1d5Smjnelson	fi
1970cdf0c1d5Smjnelson
1971cdf0c1d5Smjnelson	#
1972cdf0c1d5Smjnelson	# parent's version of the file
1973cdf0c1d5Smjnelson	#
1974cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1975cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1976cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1977cdf0c1d5Smjnelson	#
1978cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1979cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1980cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1981cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1982cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1983cdf0c1d5Smjnelson
198402d26c39SVladimir Kotal		if (( $? != 0 )); then
1985cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1986cdf0c1d5Smjnelson		else
1987cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1988cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1989cdf0c1d5Smjnelson			else
1990cdf0c1d5Smjnelson				# should never happen
1991cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1992cdf0c1d5Smjnelson			fi
1993cdf0c1d5Smjnelson		fi
1994cdf0c1d5Smjnelson	fi
1995cdf0c1d5Smjnelson}
1996cdf0c1d5Smjnelson
1997cdf0c1d5Smjnelsonfunction build_old_new_subversion
1998cdf0c1d5Smjnelson{
1999cdf0c1d5Smjnelson	typeset olddir="$1"
2000cdf0c1d5Smjnelson	typeset newdir="$2"
2001cdf0c1d5Smjnelson
2002cdf0c1d5Smjnelson	# Snag new version of file.
2003cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2004cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2005cdf0c1d5Smjnelson
2006cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2007cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2008cdf0c1d5Smjnelson	else
2009cdf0c1d5Smjnelson		# Get the parent's version of the file.
2010cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2011cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2012cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2013cdf0c1d5Smjnelson		fi
2014cdf0c1d5Smjnelson	fi
2015cdf0c1d5Smjnelson}
2016cdf0c1d5Smjnelson
2017cdf0c1d5Smjnelsonfunction build_old_new_unknown
2018cdf0c1d5Smjnelson{
2019cdf0c1d5Smjnelson	typeset olddir="$1"
2020cdf0c1d5Smjnelson	typeset newdir="$2"
2021cdf0c1d5Smjnelson
2022cdf0c1d5Smjnelson	#
2023cdf0c1d5Smjnelson	# Snag new version of file.
2024cdf0c1d5Smjnelson	#
2025cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2026cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2027cdf0c1d5Smjnelson
2028cdf0c1d5Smjnelson	#
2029cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2030cdf0c1d5Smjnelson	#
2031cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2032cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2033cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2034cdf0c1d5Smjnelson	fi
2035cdf0c1d5Smjnelson}
2036cdf0c1d5Smjnelson
2037cdf0c1d5Smjnelsonfunction build_old_new
2038cdf0c1d5Smjnelson{
2039cdf0c1d5Smjnelson	typeset WDIR=$1
2040cdf0c1d5Smjnelson	typeset PWS=$2
2041cdf0c1d5Smjnelson	typeset PDIR=$3
2042cdf0c1d5Smjnelson	typeset PF=$4
2043cdf0c1d5Smjnelson	typeset CWS=$5
2044cdf0c1d5Smjnelson	typeset DIR=$6
2045cdf0c1d5Smjnelson	typeset F=$7
2046cdf0c1d5Smjnelson
2047cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2048cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2049cdf0c1d5Smjnelson
2050cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2051cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2052cdf0c1d5Smjnelson
2053cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2054cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
2055cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
2056cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
2057cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2058cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2059cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2060cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2061cdf0c1d5Smjnelson	fi
2062cdf0c1d5Smjnelson
2063cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2064cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2065cdf0c1d5Smjnelson		return 1
2066cdf0c1d5Smjnelson	fi
2067cdf0c1d5Smjnelson	return 0
2068cdf0c1d5Smjnelson}
2069cdf0c1d5Smjnelson
2070cdf0c1d5Smjnelson
2071daaffb31Sdp#
2072daaffb31Sdp# Usage message.
2073daaffb31Sdp#
2074daaffb31Sdpfunction usage
2075daaffb31Sdp{
2076daaffb31Sdp	print 'Usage:\twebrev [common-options]
2077daaffb31Sdp	webrev [common-options] ( <file> | - )
2078daaffb31Sdp	webrev [common-options] -w <wx file>
2079daaffb31Sdp
2080daaffb31SdpOptions:
2081*0fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2082ba44d8a2SVladimir Kotal	-D: delete remote webrev
2083daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
2084*0fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2085ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2086ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2087daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2088daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
208902d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
209002d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2091daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2092daaffb31Sdp
2093daaffb31SdpEnvironment:
2094daaffb31Sdp	WDIR: Control the output directory.
2095ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2096daaffb31Sdp
2097cdf0c1d5SmjnelsonSCM Specific Options:
2098cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
2099cdf0c1d5Smjnelson
2100daaffb31SdpSCM Environment:
2101cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2102cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2103daaffb31Sdp'
2104daaffb31Sdp
2105daaffb31Sdp	exit 2
2106daaffb31Sdp}
2107daaffb31Sdp
2108daaffb31Sdp#
2109daaffb31Sdp#
2110daaffb31Sdp# Main program starts here
2111daaffb31Sdp#
2112daaffb31Sdp#
2113daaffb31Sdp
2114daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2115daaffb31Sdp
2116daaffb31Sdpset +o noclobber
2117daaffb31Sdp
2118cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
2119cdf0c1d5Smjnelson
212014983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
212114983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2122cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2123cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
212414983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
212514983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
212614983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
212702d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2128cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2129cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2130cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2131cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
213202d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2133b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
213402d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
213502d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
213602d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2137ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2138cdf0c1d5Smjnelson
2139ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2140ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2141ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
214214983201Sdp
214314983201Sdpif [[ ! -x $PERL ]]; then
214414983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
214514983201Sdp	exit 1
2146daaffb31Sdpfi
214714983201Sdp
2148cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2149cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2150cdf0c1d5Smjnelson	exit 1
2151cdf0c1d5Smjnelsonfi
2152cdf0c1d5Smjnelson
215314983201Sdp#
215414983201Sdp# These aren't fatal, but we want to note them to the user.
215514983201Sdp# We don't warn on the absence of 'wx' until later when we've
215614983201Sdp# determined that we actually need to try to invoke it.
215714983201Sdp#
215814983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
215914983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
216014983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2161daaffb31Sdp
2162daaffb31Sdp# Declare global total counters.
2163daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2164daaffb31Sdp
2165ba44d8a2SVladimir Kotal# default remote host for upload/delete
2166ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2167b0088928SVladimir Kotal# prefixes for upload targets
2168b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2169b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2170ba44d8a2SVladimir Kotal
2171*0fd2682eSMark J. NelsonCflag=
2172ba44d8a2SVladimir KotalDflag=
217314983201Sdpflist_mode=
217414983201Sdpflist_file=
2175daaffb31Sdpiflag=
2176*0fd2682eSMark J. NelsonIflag=
217702d26c39SVladimir Kotallflag=
217802d26c39SVladimir KotalNflag=
217902d26c39SVladimir Kotalnflag=
218002d26c39SVladimir KotalOflag=
2181daaffb31Sdpoflag=
2182daaffb31Sdppflag=
218302d26c39SVladimir Kotaltflag=
218402d26c39SVladimir Kotaluflag=
218502d26c39SVladimir KotalUflag=
2186daaffb31Sdpwflag=
218702d26c39SVladimir Kotalremote_target=
2188ba44d8a2SVladimir Kotal
2189ba44d8a2SVladimir Kotal#
2190ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2191ba44d8a2SVladimir Kotal# 	with usr/src/tools/onbld/hgext/cdm.py
2192ba44d8a2SVladimir Kotal#
2193*0fd2682eSMark J. Nelsonwhile getopts "C:tDi:I:lnNo:Op::Uw" opt
2194daaffb31Sdpdo
2195daaffb31Sdp	case $opt in
2196*0fd2682eSMark J. Nelson	C)	Cflag=1
2197*0fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
2198*0fd2682eSMark J. Nelson
2199ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2200ba44d8a2SVladimir Kotal
2201daaffb31Sdp	i)	iflag=1
2202daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2203daaffb31Sdp
2204*0fd2682eSMark J. Nelson	I)	Iflag=1
2205*0fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
2206*0fd2682eSMark J. Nelson
2207daaffb31Sdp	#
2208daaffb31Sdp	# If -l has been specified, we need to abort further options
2209daaffb31Sdp	# processing, because subsequent arguments are going to be
2210daaffb31Sdp	# arguments to 'putback -n'.
2211daaffb31Sdp	#
2212daaffb31Sdp	l)	lflag=1
2213daaffb31Sdp		break;;
2214daaffb31Sdp
221502d26c39SVladimir Kotal	N)	Nflag=1;;
221602d26c39SVladimir Kotal
221702d26c39SVladimir Kotal	n)	nflag=1;;
2218daaffb31Sdp
2219daaffb31Sdp	O)	Oflag=1;;
2220daaffb31Sdp
222102d26c39SVladimir Kotal	o)	oflag=1
222202d26c39SVladimir Kotal		WDIR=$OPTARG;;
222302d26c39SVladimir Kotal
222402d26c39SVladimir Kotal	p)	pflag=1
222502d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
222602d26c39SVladimir Kotal
222702d26c39SVladimir Kotal	t)	tflag=1
222802d26c39SVladimir Kotal		remote_target=$OPTARG;;
222902d26c39SVladimir Kotal
223002d26c39SVladimir Kotal	U)	Uflag=1;;
223102d26c39SVladimir Kotal
223202d26c39SVladimir Kotal	w)	wflag=1;;
22333df69ef3SDarren Moffat
2234daaffb31Sdp	?)	usage;;
2235daaffb31Sdp	esac
2236daaffb31Sdpdone
2237daaffb31Sdp
2238daaffb31SdpFLIST=/tmp/$$.flist
2239daaffb31Sdp
2240daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2241daaffb31Sdp	usage
2242daaffb31Sdpfi
2243daaffb31Sdp
224402d26c39SVladimir Kotal# more sanity checking
224502d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2246ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2247ba44d8a2SVladimir Kotal	    "without -U"
224802d26c39SVladimir Kotal	exit 1
224902d26c39SVladimir Kotalfi
225002d26c39SVladimir Kotal
2251ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2252ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
225302d26c39SVladimir Kotal	exit 1
225402d26c39SVladimir Kotalfi
225502d26c39SVladimir Kotal
2256daaffb31Sdp#
2257*0fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
2258*0fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
2259*0fd2682eSMark J. Nelson# ton of logic we can skip.
2260*0fd2682eSMark J. Nelson#
2261*0fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
2262*0fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
2263*0fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
2264*0fd2682eSMark J. Nelson#
2265*0fd2682eSMark J. Nelsonfor do_everything in 1; do
2266*0fd2682eSMark J. Nelson
2267*0fd2682eSMark J. Nelson# DO_EVERYTHING: break point
2268*0fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
2269*0fd2682eSMark J. Nelson	break
2270*0fd2682eSMark J. Nelsonfi
2271*0fd2682eSMark J. Nelson
2272*0fd2682eSMark J. Nelson#
2273daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2274daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2275daaffb31Sdp#
2276daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2277daaffb31Sdp	parent_webrev="$codemgr_parent"
2278daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2279daaffb31Sdpfi
2280daaffb31Sdp
2281daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2282daaffb31Sdp	shift $(($OPTIND - 1))
2283daaffb31Sdp
2284daaffb31Sdp	if [[ $1 == "-" ]]; then
2285daaffb31Sdp		cat > $FLIST
228614983201Sdp		flist_mode="stdin"
228714983201Sdp		flist_done=1
228814983201Sdp		shift
2289daaffb31Sdp	elif [[ -n $1 ]]; then
229014983201Sdp		if [[ ! -r $1 ]]; then
2291daaffb31Sdp			print -u2 "$1: no such file or not readable"
2292daaffb31Sdp			usage
2293daaffb31Sdp		fi
2294daaffb31Sdp		cat $1 > $FLIST
229514983201Sdp		flist_mode="file"
229614983201Sdp		flist_file=$1
229714983201Sdp		flist_done=1
229814983201Sdp		shift
2299daaffb31Sdp	else
230014983201Sdp		flist_mode="auto"
2301daaffb31Sdp	fi
2302daaffb31Sdpfi
2303daaffb31Sdp
2304daaffb31Sdp#
2305daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2306daaffb31Sdp# is in use.
2307daaffb31Sdp#
2308cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
2309cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2310cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2311cdf0c1d5Smjnelson	;;
2312cdf0c1d5Smjnelsonunknown)
2313cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2314cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2315cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
23167c478bd9Sstevel@tonic-gate		exit 1
23177c478bd9Sstevel@tonic-gate	fi
2318cdf0c1d5Smjnelson	;;
2319cdf0c1d5Smjnelson*)
2320cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2321cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2322cdf0c1d5Smjnelson		exit 1
2323cdf0c1d5Smjnelson	fi
2324cdf0c1d5Smjnelson	;;
2325cdf0c1d5Smjnelsonesac
23267c478bd9Sstevel@tonic-gate
2327daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2328daaffb31Sdp
2329daaffb31Sdpif [[ -n $lflag ]]; then
2330daaffb31Sdp	#
2331daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2332daaffb31Sdp	# then generate the file list by extracting file names from a
2333daaffb31Sdp	# putback -n.
2334daaffb31Sdp	#
2335daaffb31Sdp	shift $(($OPTIND - 1))
2336cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2337daaffb31Sdp		flist_from_teamware "$*"
2338cdf0c1d5Smjnelson	else
2339cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2340cdf0c1d5Smjnelson		exit 1
2341cdf0c1d5Smjnelson	fi
2342daaffb31Sdp	flist_done=1
2343daaffb31Sdp	shift $#
2344daaffb31Sdpelif [[ -n $wflag ]]; then
2345daaffb31Sdp	#
2346daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2347daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2348daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2349daaffb31Sdp	# in building the index.html file.
2350daaffb31Sdp	#
2351daaffb31Sdp	shift $(($OPTIND - 1))
2352daaffb31Sdp	wxfile=$1
2353daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2354daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2355daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2356daaffb31Sdp		fi
2357daaffb31Sdp	fi
2358daaffb31Sdp
2359daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2360daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2361daaffb31Sdp
2362cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2363cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2364cdf0c1d5Smjnelson		usage
2365cdf0c1d5Smjnelson	fi
2366cdf0c1d5Smjnelson
2367daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2368daaffb31Sdp	flist_from_wx $wxfile
2369daaffb31Sdp	flist_done=1
2370daaffb31Sdp	if [[ -n "$*" ]]; then
2371daaffb31Sdp		shift
2372daaffb31Sdp	fi
237314983201Sdpelif [[ $flist_mode == "stdin" ]]; then
237414983201Sdp	print -u2 " File list from: standard input"
237514983201Sdpelif [[ $flist_mode == "file" ]]; then
237614983201Sdp	print -u2 " File list from: $flist_file"
2377daaffb31Sdpfi
2378daaffb31Sdp
2379daaffb31Sdpif [[ $# -gt 0 ]]; then
238014983201Sdp	print -u2 "WARNING: unused arguments: $*"
2381daaffb31Sdpfi
2382daaffb31Sdp
2383daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
2384daaffb31Sdp	#
2385daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
2386daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
2387daaffb31Sdp	#
2388daaffb31Sdp	#      1) on the command line (only for the parent)
2389daaffb31Sdp	#      2) in the user environment
2390daaffb31Sdp	#      3) in the flist
2391daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
2392daaffb31Sdp	#
2393daaffb31Sdp
2394daaffb31Sdp	#
2395daaffb31Sdp	# Here is case (2): the user environment
2396daaffb31Sdp	#
2397daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2398daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2399daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
24007c478bd9Sstevel@tonic-gate		exit 1
24017c478bd9Sstevel@tonic-gate	fi
24027c478bd9Sstevel@tonic-gate
2403daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2404daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2405daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2406daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
24077c478bd9Sstevel@tonic-gate		exit 1
24087c478bd9Sstevel@tonic-gate	fi
24097c478bd9Sstevel@tonic-gate
2410daaffb31Sdp	#
2411daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2412daaffb31Sdp	# list, then see if we can get it by probing for wx.
2413daaffb31Sdp	#
241414983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
241514983201Sdp		if [[ ! -x $WX ]]; then
241614983201Sdp			print -u2 "WARNING: wx not found!"
2417daaffb31Sdp		fi
24187c478bd9Sstevel@tonic-gate
2419daaffb31Sdp		#
2420daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2421daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2422daaffb31Sdp		# hang asking us to initialize our wx information.
2423daaffb31Sdp		#
242414983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2425daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2426daaffb31Sdp			$WX list -w > $FLIST
2427daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2428daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2429daaffb31Sdp			print -u2 "done"
2430daaffb31Sdp			flist_done=1
2431daaffb31Sdp		fi
2432daaffb31Sdp	fi
2433daaffb31Sdp
2434daaffb31Sdp	#
2435daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2436daaffb31Sdp	# from the command line), eval it to extract environment variables from
2437daaffb31Sdp	# it: This is step (3).
2438daaffb31Sdp	#
2439daaffb31Sdp	env_from_flist
2440daaffb31Sdp
2441daaffb31Sdp	#
2442daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2443daaffb31Sdp	# it from teamware.
2444daaffb31Sdp	#
2445daaffb31Sdp	if [[ -z $flist_done ]]; then
2446daaffb31Sdp		flist_from_teamware
2447daaffb31Sdp		env_from_flist
2448daaffb31Sdp	fi
2449daaffb31Sdp
2450daaffb31Sdp	#
2451daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2452daaffb31Sdp	# from workspace.
2453daaffb31Sdp	#
2454cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2455daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2456daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2457daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2458daaffb31Sdp		exit 1
2459daaffb31Sdp	fi
2460daaffb31Sdp
2461daaffb31Sdp	#
2462cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2463cdf0c1d5Smjnelson	# webrev title.
2464cdf0c1d5Smjnelson	#
2465cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2466cdf0c1d5Smjnelson
2467cdf0c1d5Smjnelson	#
2468daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2469daaffb31Sdp	#
2470daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2471daaffb31Sdp	CWS=$codemgr_ws
2472daaffb31Sdp	PWS=$codemgr_parent
2473cdf0c1d5Smjnelson
2474cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2475cdf0c1d5Smjnelson
2476cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2477cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2478cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2479cdf0c1d5Smjnelson
2480cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2481cdf0c1d5Smjnelson
2482cdf0c1d5Smjnelson	#
2483cdf0c1d5Smjnelson	# Parent can either be specified with -p
2484cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2485cdf0c1d5Smjnelson	# or taken from hg's default path.
2486cdf0c1d5Smjnelson	#
2487cdf0c1d5Smjnelson
2488cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2489cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2490cdf0c1d5Smjnelson	fi
2491cdf0c1d5Smjnelson
2492cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2493cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2494cdf0c1d5Smjnelson	fi
2495cdf0c1d5Smjnelson
2496cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2497cdf0c1d5Smjnelson	CWS=$codemgr_ws
2498cdf0c1d5Smjnelson	PWS=$codemgr_parent
2499cdf0c1d5Smjnelson
2500cdf0c1d5Smjnelson	#
2501cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2502cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2503cdf0c1d5Smjnelson	#
2504cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2505cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2506cdf0c1d5Smjnelson	else
2507cdf0c1d5Smjnelson		real_parent=$PWS
2508cdf0c1d5Smjnelson	fi
2509cdf0c1d5Smjnelson
2510cdf0c1d5Smjnelson	#
2511cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2512cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2513cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2514cdf0c1d5Smjnelson	# files mentioned in the flist.
2515cdf0c1d5Smjnelson	#
2516cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2517cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2518cdf0c1d5Smjnelson		flist_done=1
2519cdf0c1d5Smjnelson	fi
2520cdf0c1d5Smjnelson
2521cdf0c1d5Smjnelson	#
2522cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2523cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2524cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2525cdf0c1d5Smjnelson	# in the user-specified flist.
2526cdf0c1d5Smjnelson	#
2527cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2528cdf0c1d5Smjnelson		env_from_flist
2529cdf0c1d5Smjnelson	fi
2530cdf0c1d5Smjnelson
2531cdf0c1d5Smjnelson	#
2532cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2533cdf0c1d5Smjnelson	#
2534cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2535cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2536cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2537cdf0c1d5Smjnelson		print " Done."
2538cdf0c1d5Smjnelson	fi
2539cdf0c1d5Smjnelson
2540cdf0c1d5Smjnelson	#
2541cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2542cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2543cdf0c1d5Smjnelson	# if we don't have one.
2544cdf0c1d5Smjnelson	#
2545cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2546b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2547cdf0c1d5Smjnelson	fi
2548cdf0c1d5Smjnelson
2549cdf0c1d5Smjnelson	#
2550cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2551cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2552cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2553cdf0c1d5Smjnelson	#
2554cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2555cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2556b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2557cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2558cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2559cdf0c1d5Smjnelson		exit 1
2560cdf0c1d5Smjnelson	fi
2561cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2562cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2563cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2564cdf0c1d5Smjnelson	else
2565cdf0c1d5Smjnelson		svn info | while read line; do
2566cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2567cdf0c1d5Smjnelson				url=${line#URL: }
2568cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2569cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2570cdf0c1d5Smjnelson			fi
2571cdf0c1d5Smjnelson		done
2572cdf0c1d5Smjnelson
2573cdf0c1d5Smjnelson		rel=${url#$repo}
2574cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2575cdf0c1d5Smjnelson	fi
2576cdf0c1d5Smjnelson
2577cdf0c1d5Smjnelson	#
2578cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2579cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2580cdf0c1d5Smjnelson	#
2581cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2582cdf0c1d5Smjnelson
2583cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2584cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2585cdf0c1d5Smjnelson	fi
2586cdf0c1d5Smjnelsonelse
2587cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2588cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2589cdf0c1d5Smjnelson    else
2590cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2591cdf0c1d5Smjnelson    fi
2592cdf0c1d5Smjnelson
2593cdf0c1d5Smjnelson    env_from_flist
2594cdf0c1d5Smjnelson
2595cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2596cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2597cdf0c1d5Smjnelson	exit 1
2598cdf0c1d5Smjnelson    fi
2599cdf0c1d5Smjnelson
2600cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2601cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2602cdf0c1d5Smjnelson	exit 1
2603cdf0c1d5Smjnelson    fi
2604cdf0c1d5Smjnelson
2605cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2606cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2607daaffb31Sdpfi
2608daaffb31Sdp
2609daaffb31Sdp#
2610daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2611daaffb31Sdp# webrev-info file in the workspace directory.
2612daaffb31Sdp#
2613daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2614daaffb31Sdp	iflag=1
2615daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2616daaffb31Sdpfi
2617daaffb31Sdp
2618daaffb31Sdpif [[ -n $iflag ]]; then
2619daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2620daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2621daaffb31Sdp		    "not readable."
2622daaffb31Sdp		exit 1
2623daaffb31Sdp	else
2624daaffb31Sdp		#
2625daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2626daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2627daaffb31Sdp		#
2628daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2629daaffb31Sdp	fi
2630daaffb31Sdpfi
2631daaffb31Sdp
2632*0fd2682eSMark J. Nelson# DO_EVERYTHING: break point
2633*0fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
2634*0fd2682eSMark J. Nelson	break
2635*0fd2682eSMark J. Nelsonfi
2636*0fd2682eSMark J. Nelson
2637*0fd2682eSMark J. Nelsontypeset -A itsinfo
2638*0fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
2639*0fd2682eSMark J. Nelsonvalid_prefixes=
2640*0fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
2641*0fd2682eSMark J. Nelson	DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
2642*0fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
2643*0fd2682eSMark J. Nelson		REGFILE=$ITSREG
2644*0fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
2645*0fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
2646*0fd2682eSMark J. Nelson	else
2647*0fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
2648*0fd2682eSMark J. Nelson	fi
2649*0fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
2650*0fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
2651*0fd2682eSMark J. Nelson		exit 1
2652*0fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
2653*0fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
2654*0fd2682eSMark J. Nelson	fi
2655*0fd2682eSMark J. Nelson
2656*0fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
2657*0fd2682eSMark J. Nelson
2658*0fd2682eSMark J. Nelson		name=${LINE%%=*}
2659*0fd2682eSMark J. Nelson		value="${LINE#*=}"
2660*0fd2682eSMark J. Nelson
2661*0fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
2662*0fd2682eSMark J. Nelson			p=${value}
2663*0fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
2664*0fd2682eSMark J. Nelson		else
2665*0fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
2666*0fd2682eSMark J. Nelson		fi
2667*0fd2682eSMark J. Nelson	done
2668*0fd2682eSMark J. Nelson
2669*0fd2682eSMark J. Nelson
2670*0fd2682eSMark J. Nelson	DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
2671*0fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
2672*0fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
2673*0fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
2674*0fd2682eSMark J. Nelson	fi
2675*0fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
2676*0fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
2677*0fd2682eSMark J. Nelson	fi
2678*0fd2682eSMark J. Nelson	its_domain=
2679*0fd2682eSMark J. Nelson	its_priority=
2680*0fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
2681*0fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
2682*0fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
2683*0fd2682eSMark J. Nelson			exit 1
2684*0fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
2685*0fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
2686*0fd2682eSMark J. Nelson		fi
2687*0fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
2688*0fd2682eSMark J. Nelson		    eval "${LINE}"
2689*0fd2682eSMark J. Nelson		done
2690*0fd2682eSMark J. Nelson	done
2691*0fd2682eSMark J. Nelson
2692*0fd2682eSMark J. Nelson	#
2693*0fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
2694*0fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
2695*0fd2682eSMark J. Nelson	#
2696*0fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
2697*0fd2682eSMark J. Nelson	#
2698*0fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
2699*0fd2682eSMark J. Nelson		#
2700*0fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
2701*0fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
2702*0fd2682eSMark J. Nelson		#
2703*0fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
2704*0fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
2705*0fd2682eSMark J. Nelson		else
2706*0fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
2707*0fd2682eSMark J. Nelson		fi
2708*0fd2682eSMark J. Nelson
2709*0fd2682eSMark J. Nelson		#
2710*0fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
2711*0fd2682eSMark J. Nelson		# to this information tracking system should resolve through
2712*0fd2682eSMark J. Nelson		# the same URL.
2713*0fd2682eSMark J. Nelson		#
2714*0fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
2715*0fd2682eSMark J. Nelson		#
2716*0fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
2717*0fd2682eSMark J. Nelson		# INTERNAL_URL.
2718*0fd2682eSMark J. Nelson		#
2719*0fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
2720*0fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
2721*0fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
2722*0fd2682eSMark J. Nelson				break
2723*0fd2682eSMark J. Nelson			fi
2724*0fd2682eSMark J. Nelson		done
2725*0fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
2726*0fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
2727*0fd2682eSMark J. Nelson		fi
2728*0fd2682eSMark J. Nelson
2729*0fd2682eSMark J. Nelson		#
2730*0fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
2731*0fd2682eSMark J. Nelson		#
2732*0fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
2733*0fd2682eSMark J. Nelson
2734*0fd2682eSMark J. Nelson		print "/^${p}[ 	]/ {
2735*0fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
2736*0fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
2737*0fd2682eSMark J. Nelson			}" >> ${its_sed_script}
2738*0fd2682eSMark J. Nelson	done
2739*0fd2682eSMark J. Nelson
2740*0fd2682eSMark J. Nelson	#
2741*0fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
2742*0fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
2743*0fd2682eSMark J. Nelson	#
2744*0fd2682eSMark J. Nelson	for p in ${its_priority}; do
2745*0fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
2746*0fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
2747*0fd2682eSMark J. Nelson			}" >> ${its_sed_script}
2748*0fd2682eSMark J. Nelson	done
2749*0fd2682eSMark J. Nelsonfi
2750*0fd2682eSMark J. Nelson
2751*0fd2682eSMark J. Nelson#
2752*0fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
2753*0fd2682eSMark J. Nelson# and explanation of this terminator.
2754*0fd2682eSMark J. Nelson#
2755*0fd2682eSMark J. Nelsondone
2756*0fd2682eSMark J. Nelson
2757daaffb31Sdp#
2758daaffb31Sdp# Output directory.
2759daaffb31Sdp#
2760daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2761daaffb31Sdp
2762daaffb31Sdp#
276302d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
276402d26c39SVladimir Kotal# in the future this could potentially be an option.
2765daaffb31Sdp#
276602d26c39SVladimir Kotalif [[ -n $oflag ]]; then
276702d26c39SVladimir Kotal	WNAME=${WDIR##*/}
276802d26c39SVladimir Kotalelse
2769daaffb31Sdp	WNAME=${CWS##*/}
277002d26c39SVladimir Kotalfi
277102d26c39SVladimir Kotal
2772ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2773ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2774b0088928SVladimir Kotal	#
2775ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2776ba44d8a2SVladimir Kotal	# the default values.
2777b0088928SVladimir Kotal	#
2778ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2779ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2780ba44d8a2SVladimir Kotal	else
2781b0088928SVladimir Kotal		#
2782b0088928SVladimir Kotal		# Check upload target prefix first.
2783b0088928SVladimir Kotal		#
2784b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
2785b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
2786b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
2787b0088928SVladimir Kotal			    "($remote_target)"
2788b0088928SVladimir Kotal			exit 1
2789b0088928SVladimir Kotal		fi
2790b0088928SVladimir Kotal		#
2791ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2792ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2793ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2794ba44d8a2SVladimir Kotal		# local webrev directory name.
2795b0088928SVladimir Kotal		#
2796b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
2797b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
2798ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2799b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
2800ba44d8a2SVladimir Kotal			fi
2801b0088928SVladimir Kotal		else
2802b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
2803b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
2804b0088928SVladimir Kotal					"($remote_target)"
2805b0088928SVladimir Kotal				exit 1
2806b0088928SVladimir Kotal			else
2807b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
2808ba44d8a2SVladimir Kotal			fi
2809ba44d8a2SVladimir Kotal		fi
2810ba44d8a2SVladimir Kotal	fi
2811ba44d8a2SVladimir Kotal
2812b0088928SVladimir Kotal	#
2813b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
2814b0088928SVladimir Kotal	# specification separately.
2815b0088928SVladimir Kotal	#
2816b0088928SVladimir Kotal	remote_target=${remote_target%/}
2817b0088928SVladimir Kotalfi
2818b0088928SVladimir Kotal
2819b0088928SVladimir Kotal#
2820ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2821b0088928SVladimir Kotal#
2822ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2823b0088928SVladimir Kotal	delete_webrev 1 1
2824ba44d8a2SVladimir Kotal	exit $?
2825ba44d8a2SVladimir Kotalfi
2826ba44d8a2SVladimir Kotal
2827b0088928SVladimir Kotal#
2828ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2829b0088928SVladimir Kotal#
2830ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2831ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2832b0088928SVladimir Kotal		delete_webrev 1 1
2833ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2834ba44d8a2SVladimir Kotal	fi
2835ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
283602d26c39SVladimir Kotal		upload_webrev
283702d26c39SVladimir Kotal		exit $?
283802d26c39SVladimir Kotal	fi
2839ba44d8a2SVladimir Kotalfi
2840daaffb31Sdp
2841e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
28427c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
28437c478bd9Sstevel@tonic-gatefi
2844daaffb31Sdp
2845daaffb31Sdpif [[ ! -d $WDIR ]]; then
2846daaffb31Sdp	mkdir -p $WDIR
2847ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
28487c478bd9Sstevel@tonic-gatefi
28497c478bd9Sstevel@tonic-gate
2850daaffb31Sdp#
2851daaffb31Sdp# Summarize what we're going to do.
2852daaffb31Sdp#
2853cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2854cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2855cdf0c1d5Smjnelsonelse
2856daaffb31Sdp	print "      Workspace: $CWS"
2857cdf0c1d5Smjnelsonfi
2858daaffb31Sdpif [[ -n $parent_webrev ]]; then
2859daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2860daaffb31Sdpelse
2861cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2862cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2863b0088928SVladimir Kotal			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2864cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2865cdf0c1d5Smjnelson	else
2866daaffb31Sdp		print "Compare against: $PWS"
2867daaffb31Sdp	fi
2868cdf0c1d5Smjnelsonfi
2869daaffb31Sdp
2870daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2871daaffb31Sdpprint "      Output to: $WDIR"
2872daaffb31Sdp
2873daaffb31Sdp#
28747c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2875daaffb31Sdp#
2876daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
28777c478bd9Sstevel@tonic-gate
2878daaffb31Sdprm -f $WDIR/$WNAME.patch
2879daaffb31Sdprm -f $WDIR/$WNAME.ps
2880daaffb31Sdprm -f $WDIR/$WNAME.pdf
28817c478bd9Sstevel@tonic-gate
2882daaffb31Sdptouch $WDIR/$WNAME.patch
28837c478bd9Sstevel@tonic-gate
2884daaffb31Sdpprint "   Output Files:"
2885daaffb31Sdp
2886daaffb31Sdp#
2887daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2888daaffb31Sdp#
2889b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2890daaffb31SdpFLIST=/tmp/$$.flist.clean
2891daaffb31Sdp
2892daaffb31Sdp#
2893cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2894cdf0c1d5Smjnelson#
2895cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2896cdf0c1d5Smjnelson	#
2897cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2898cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2899cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2900cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2901cdf0c1d5Smjnelson	#    keep only the old name.
2902cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2903cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2904cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2905cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2906cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2907cdf0c1d5Smjnelson	#
2908cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2909b0088928SVladimir Kotal	$SED '
2910cdf0c1d5Smjnelson		s#^[^ ]* ##
2911cdf0c1d5Smjnelson		s#/#\\\/#g
2912cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2913cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2914cdf0c1d5Smjnelson
2915cdf0c1d5Smjnelson	#
2916cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2917cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2918cdf0c1d5Smjnelson	#
2919cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2920cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2921b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2922cdf0c1d5Smjnelsonfi
2923cdf0c1d5Smjnelson
2924cdf0c1d5Smjnelson#
2925daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2926daaffb31Sdp#
2927daaffb31Sdpcat $FLIST | while read LINE
29287c478bd9Sstevel@tonic-gatedo
29297c478bd9Sstevel@tonic-gate	set - $LINE
29307c478bd9Sstevel@tonic-gate	P=$1
29317c478bd9Sstevel@tonic-gate
2932daaffb31Sdp	#
2933daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2934daaffb31Sdp	# file that has been modified or created in the child.  A file
2935daaffb31Sdp	# that is renamed in the child workspace has two names on the
2936daaffb31Sdp	# line: new name followed by the old name.
2937daaffb31Sdp	#
2938daaffb31Sdp	oldname=""
2939daaffb31Sdp	oldpath=""
2940daaffb31Sdp	rename=
2941daaffb31Sdp	if [[ $# -eq 2 ]]; then
29427c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2943daaffb31Sdp		oldname=" (was $PP)"
2944daaffb31Sdp		oldpath="$PP"
2945daaffb31Sdp		rename=1
29467c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2947daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
29487c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
29497c478bd9Sstevel@tonic-gate		fi
29507c478bd9Sstevel@tonic-gate
29517c478bd9Sstevel@tonic-gate		PF=${PP##*/}
29527c478bd9Sstevel@tonic-gate
29537c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2954daaffb31Sdp	        if [[ $DIR == $P ]]; then
29557c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
29567c478bd9Sstevel@tonic-gate		fi
29577c478bd9Sstevel@tonic-gate
29587c478bd9Sstevel@tonic-gate		F=${P##*/}
2959daaffb31Sdp
29607c478bd9Sstevel@tonic-gate        else
29617c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2962daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
29637c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
29647c478bd9Sstevel@tonic-gate		fi
29657c478bd9Sstevel@tonic-gate
29667c478bd9Sstevel@tonic-gate		F=${P##*/}
29677c478bd9Sstevel@tonic-gate
29687c478bd9Sstevel@tonic-gate		PP=$P
29697c478bd9Sstevel@tonic-gate		PDIR=$DIR
29707c478bd9Sstevel@tonic-gate		PF=$F
29717c478bd9Sstevel@tonic-gate	fi
29727c478bd9Sstevel@tonic-gate
2973daaffb31Sdp	COMM=`getcomments html $P $PP`
29747c478bd9Sstevel@tonic-gate
2975daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
29767c478bd9Sstevel@tonic-gate
29777c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
29787c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
29797c478bd9Sstevel@tonic-gate
2980daaffb31Sdp	#
2981daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2982daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2983e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2984daaffb31Sdp	#
2985e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2986daaffb31Sdp		pclosed=${P##usr/closed/}
2987e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2988e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2989daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2990daaffb31Sdp			    "mode review"
2991daaffb31Sdp			continue
2992daaffb31Sdp		fi
2993daaffb31Sdp	fi
2994daaffb31Sdp
2995daaffb31Sdp	#
2996cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2997daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2998daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2999daaffb31Sdp	#
3000daaffb31Sdp
3001cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
30027c478bd9Sstevel@tonic-gate	    continue
30037c478bd9Sstevel@tonic-gate
3004cdf0c1d5Smjnelson	#
3005cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3006cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3007cdf0c1d5Smjnelson	# consistent environment.
3008cdf0c1d5Smjnelson	#
3009cdf0c1d5Smjnelson	OWD=$PWD
3010daaffb31Sdp	cd $WDIR/raw_files
3011daaffb31Sdp	ofile=old/$PDIR/$PF
3012daaffb31Sdp	nfile=new/$DIR/$F
30137c478bd9Sstevel@tonic-gate
3014daaffb31Sdp	mv_but_nodiff=
3015daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3016daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3017daaffb31Sdp		mv_but_nodiff=1
3018daaffb31Sdp	fi
3019daaffb31Sdp
3020daaffb31Sdp	#
3021daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3022daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3023daaffb31Sdp	#
3024daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3025daaffb31Sdp	#	  diff and an 'add' diff
3026daaffb31Sdp	#	- new files and deleted files must be handled specially
3027daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
3028daaffb31Sdp	#	  (and hence renames) as of this writing.
3029daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
3030daaffb31Sdp	#	  output of Solaris diff properly when it comes to
3031daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
3032daaffb31Sdp	#         transformations:
3033daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3034daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3035daaffb31Sdp	#
3036b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3037b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3038daaffb31Sdp
3039daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3040daaffb31Sdp	if [[ -z $rename ]]; then
3041e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3042daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3043daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3044e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3045daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3046daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3047daaffb31Sdp		else
3048daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3049daaffb31Sdp		fi
3050daaffb31Sdp	else
3051daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3052daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3053daaffb31Sdp
3054daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3055daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3056daaffb31Sdp
3057daaffb31Sdp	fi
3058daaffb31Sdp
3059daaffb31Sdp	#
3060daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3061daaffb31Sdp	# whole wad.
3062daaffb31Sdp	#
3063daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3064daaffb31Sdp
3065daaffb31Sdp	print " patch\c"
3066daaffb31Sdp
3067daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3068daaffb31Sdp
3069daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3070daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3071daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
30727c478bd9Sstevel@tonic-gate		print " cdiffs\c"
30737c478bd9Sstevel@tonic-gate
3074daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3075daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3076daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
3077daaffb31Sdp
30787c478bd9Sstevel@tonic-gate		print " udiffs\c"
30797c478bd9Sstevel@tonic-gate
30807c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3081daaffb31Sdp			$WDIFF -c "$COMM" \
3082daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3083daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3084daaffb31Sdp			if [[ $? -eq 0 ]]; then
30857c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3086daaffb31Sdp			else
3087daaffb31Sdp				print " wdiffs[fail]\c"
3088daaffb31Sdp			fi
30897c478bd9Sstevel@tonic-gate		fi
30907c478bd9Sstevel@tonic-gate
3091daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3092daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
30937c478bd9Sstevel@tonic-gate		print " sdiffs\c"
30947c478bd9Sstevel@tonic-gate
30957c478bd9Sstevel@tonic-gate		print " frames\c"
30967c478bd9Sstevel@tonic-gate
30977c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
30987c478bd9Sstevel@tonic-gate
3099daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3100daaffb31Sdp
3101daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3102daaffb31Sdp		# renamed file: may also have differences
3103daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3104daaffb31Sdp	elif [[ -f $nfile ]]; then
31057c478bd9Sstevel@tonic-gate		# new file: count added lines
3106daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3107daaffb31Sdp	elif [[ -f $ofile ]]; then
31087c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3109daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
31107c478bd9Sstevel@tonic-gate	fi
31117c478bd9Sstevel@tonic-gate
3112daaffb31Sdp	#
3113daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3114daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3115daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3116daaffb31Sdp	#
3117daaffb31Sdp	if [[ -f $nfile ]]; then
3118daaffb31Sdp		ocr=$ofile
3119daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3120daaffb31Sdp
3121daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3122daaffb31Sdp			textcomm=`getcomments text $P $PP`
312314983201Sdp			if [[ -x $CODEREVIEW ]]; then
312414983201Sdp				$CODEREVIEW -y "$textcomm" \
312514983201Sdp				    -e $ocr $nfile \
312614983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
312714983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3128daaffb31Sdp				if [[ $? -eq 0 ]]; then
3129daaffb31Sdp					print " ps\c"
3130daaffb31Sdp				else
3131daaffb31Sdp					print " ps[fail]\c"
3132daaffb31Sdp				fi
3133daaffb31Sdp			fi
3134daaffb31Sdp		fi
313514983201Sdp	fi
3136daaffb31Sdp
3137cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3138cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
31397c478bd9Sstevel@tonic-gate		print " old\c"
31407c478bd9Sstevel@tonic-gate	fi
31417c478bd9Sstevel@tonic-gate
3142daaffb31Sdp	if [[ -f $nfile ]]; then
3143daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
31447c478bd9Sstevel@tonic-gate		print " new\c"
31457c478bd9Sstevel@tonic-gate	fi
31467c478bd9Sstevel@tonic-gate
3147cdf0c1d5Smjnelson	cd $OWD
3148cdf0c1d5Smjnelson
3149daaffb31Sdp	print
31507c478bd9Sstevel@tonic-gatedone
31517c478bd9Sstevel@tonic-gate
3152daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
31537c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3154daaffb31Sdp
315514983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
315614983201Sdp	print " Generating PDF: Skipped: no output available"
315714983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
315814983201Sdp	print " Generating PDF: \c"
315914983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3160daaffb31Sdp	print "Done."
316114983201Sdpelse
316214983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
316314983201Sdpfi
31647c478bd9Sstevel@tonic-gate
3165e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3166e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3167e0e0293aSjmcp
3168e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3169ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3170e0e0293aSjmcpfi
3171e0e0293aSjmcp
31727c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
31737c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
31747c478bd9Sstevel@tonic-gate
31757c478bd9Sstevel@tonic-gatecd $CWS
31767c478bd9Sstevel@tonic-gate
31777c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3178daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
31797c478bd9Sstevel@tonic-gate
3180daaffb31Sdpprint "     index.html: \c"
31817c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
31827c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
31837c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
31847c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
31857c478bd9Sstevel@tonic-gate
3186daaffb31Sdpprint "$HTML<head>$STDHEAD"
3187daaffb31Sdpprint "<title>$WNAME</title>"
3188daaffb31Sdpprint "</head>"
3189daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3190daaffb31Sdpprint "<div class=\"summary\">"
3191daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
31927c478bd9Sstevel@tonic-gate
3193daaffb31Sdpprint "<table>"
31947c478bd9Sstevel@tonic-gate
3195daaffb31Sdp#
3196cdf0c1d5Smjnelson# Get the preparer's name:
3197daaffb31Sdp#
3198cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3199cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3200cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3201cdf0c1d5Smjnelson#
3202cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3203cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3204cdf0c1d5Smjnelson#
3205cdf0c1d5Smjnelsonpreparer=
3206cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3207cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3208cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3209cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3210cdf0c1d5Smjnelson	fi
3211cdf0c1d5Smjnelsonfi
3212cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3213cdf0c1d5Smjnelson	preparer=$(
3214cdf0c1d5Smjnelson	    $PERL -e '
3215cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3216cdf0c1d5Smjnelson	        if ($login) {
3217cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3218cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3219cdf0c1d5Smjnelson	        } else {
3220cdf0c1d5Smjnelson	            printf "(unknown)\n";
3221cdf0c1d5Smjnelson	        }
3222cdf0c1d5Smjnelson	')
3223daaffb31Sdpfi
3224daaffb31Sdp
3225cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
3226cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
3227cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
3228cdf0c1d5Smjnelson	print "(at $CWS_REV)"
3229cdf0c1d5Smjnelsonfi
3230cdf0c1d5Smjnelsonprint "</td></tr>"
3231daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3232daaffb31Sdpif [[ -n $parent_webrev ]]; then
3233daaffb31Sdp	print "webrev at $parent_webrev"
3234daaffb31Sdpelse
3235daaffb31Sdp	print "$PWS"
3236cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
3237cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
3238cdf0c1d5Smjnelson	fi
3239daaffb31Sdpfi
3240daaffb31Sdpprint "</td></tr>"
3241daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3242daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3243daaffb31Sdpprint "</td></tr>"
3244daaffb31Sdp
3245daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3246371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3247daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3248371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3249daaffb31Sdpfi
3250daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3251371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3252daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3253371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3254daaffb31Sdpfi
3255daaffb31Sdp
3256daaffb31Sdpif [[ -n "$iflag" ]]; then
3257daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3258daaffb31Sdp	cat /tmp/$$.include
3259daaffb31Sdp	print "</div></td></tr>"
3260daaffb31Sdpfi
3261daaffb31Sdpprint "</table>"
3262daaffb31Sdpprint "</div>"
3263daaffb31Sdp
3264daaffb31Sdp#
3265daaffb31Sdp# Second pass through the files: generate the rest of the index file
3266daaffb31Sdp#
3267daaffb31Sdpcat $FLIST | while read LINE
32687c478bd9Sstevel@tonic-gatedo
32697c478bd9Sstevel@tonic-gate	set - $LINE
32707c478bd9Sstevel@tonic-gate	P=$1
32717c478bd9Sstevel@tonic-gate
3272daaffb31Sdp	if [[ $# == 2 ]]; then
32737c478bd9Sstevel@tonic-gate		PP=$2
3274cdf0c1d5Smjnelson		oldname="$PP"
32757c478bd9Sstevel@tonic-gate	else
32767c478bd9Sstevel@tonic-gate		PP=$P
3277daaffb31Sdp		oldname=""
3278daaffb31Sdp	fi
3279daaffb31Sdp
3280cdf0c1d5Smjnelson	mv_but_nodiff=
3281cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3282cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3283cdf0c1d5Smjnelson		mv_but_nodiff=1
3284cdf0c1d5Smjnelson	fi
3285cdf0c1d5Smjnelson
3286daaffb31Sdp	DIR=${P%/*}
3287daaffb31Sdp	if [[ $DIR == $P ]]; then
3288daaffb31Sdp		DIR="."   # File at root of workspace
32897c478bd9Sstevel@tonic-gate	fi
32907c478bd9Sstevel@tonic-gate
32917c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
32927c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
32937c478bd9Sstevel@tonic-gate	# appear twice in the file list
32947c478bd9Sstevel@tonic-gate
32957c478bd9Sstevel@tonic-gate	F=$WDIR/$P
32967c478bd9Sstevel@tonic-gate
3297daaffb31Sdp	print "<p>"
32987c478bd9Sstevel@tonic-gate
32997c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
33007c478bd9Sstevel@tonic-gate
3301daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3302371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3303371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3304371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3305371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
33067c478bd9Sstevel@tonic-gate
3307daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3308371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3309371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
33107c478bd9Sstevel@tonic-gate		fi
33117c478bd9Sstevel@tonic-gate
3312371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3313371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
33147c478bd9Sstevel@tonic-gate
3315371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3316371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
33177c478bd9Sstevel@tonic-gate	else
3318daaffb31Sdp		print " ------ ------ ------"
33197c478bd9Sstevel@tonic-gate
3320daaffb31Sdp		if [[ -x $WDIFF ]]; then
33217c478bd9Sstevel@tonic-gate			print " ------"
33227c478bd9Sstevel@tonic-gate		fi
3323daaffb31Sdp
3324daaffb31Sdp		print " ------"
33257c478bd9Sstevel@tonic-gate	fi
33267c478bd9Sstevel@tonic-gate
33277c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
33287c478bd9Sstevel@tonic-gate
3329daaffb31Sdp	if [[ -f $F-.html ]]; then
3330371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3331371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
33327c478bd9Sstevel@tonic-gate	else
3333daaffb31Sdp		print " ---"
33347c478bd9Sstevel@tonic-gate	fi
33357c478bd9Sstevel@tonic-gate
33367c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
33377c478bd9Sstevel@tonic-gate
3338daaffb31Sdp	if [[ -f $F.html ]]; then
3339371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3340371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
33417c478bd9Sstevel@tonic-gate	else
3342daaffb31Sdp		print " ---"
33437c478bd9Sstevel@tonic-gate	fi
33447c478bd9Sstevel@tonic-gate
3345daaffb31Sdp	if [[ -f $F.patch ]]; then
3346371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3347371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3348daaffb31Sdp	else
3349daaffb31Sdp		print " -----"
3350daaffb31Sdp	fi
3351daaffb31Sdp
3352daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3353371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3354371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3355daaffb31Sdp	else
3356daaffb31Sdp		print " ---"
3357daaffb31Sdp	fi
3358daaffb31Sdp
3359cdf0c1d5Smjnelson	print "<b>$P</b>"
3360cdf0c1d5Smjnelson
3361cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3362cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
3363cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3364cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
3365cdf0c1d5Smjnelson		else
3366cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
3367cdf0c1d5Smjnelson		fi
3368cdf0c1d5Smjnelson	fi
3369cdf0c1d5Smjnelson
3370cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3371cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3372cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3373cdf0c1d5Smjnelson	fi
3374daaffb31Sdp
3375daaffb31Sdp	#
3376e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3377daaffb31Sdp	#
3378daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3379e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3380e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3381daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3382daaffb31Sdp			    "this review</i>"
3383daaffb31Sdp		fi
3384daaffb31Sdp	fi
3385daaffb31Sdp
3386daaffb31Sdp	print "</p>"
33877c478bd9Sstevel@tonic-gate	# Insert delta comments
33887c478bd9Sstevel@tonic-gate
3389daaffb31Sdp	print "<blockquote><pre>"
3390daaffb31Sdp	getcomments html $P $PP
3391daaffb31Sdp	print "</pre>"
33927c478bd9Sstevel@tonic-gate
33937c478bd9Sstevel@tonic-gate	# Add additional comments comment
33947c478bd9Sstevel@tonic-gate
3395daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
33967c478bd9Sstevel@tonic-gate
33977c478bd9Sstevel@tonic-gate	# Add count of changes.
33987c478bd9Sstevel@tonic-gate
3399daaffb31Sdp	if [[ -f $F.count ]]; then
34007c478bd9Sstevel@tonic-gate	    cat $F.count
34017c478bd9Sstevel@tonic-gate	    rm $F.count
34027c478bd9Sstevel@tonic-gate	fi
3403cdf0c1d5Smjnelson
3404cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3405cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3406cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3407cdf0c1d5Smjnelson
3408cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3409cdf0c1d5Smjnelson		# 1) New executable files
3410cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3411cdf0c1d5Smjnelson		# 3) Existing executable files
3412cdf0c1d5Smjnelson
3413cdf0c1d5Smjnelson		old_mode=
3414cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3415cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3416cdf0c1d5Smjnelson		fi
3417cdf0c1d5Smjnelson
3418cdf0c1d5Smjnelson		new_mode=
3419cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3420cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3421cdf0c1d5Smjnelson		fi
3422cdf0c1d5Smjnelson
3423cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3424cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3425cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3426cdf0c1d5Smjnelson			print "</span>"
3427cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3428cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3429cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3430cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3431cdf0c1d5Smjnelson			print "</span>"
3432cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3433cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3434cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3435cdf0c1d5Smjnelson			print "</span>"
3436cdf0c1d5Smjnelson		fi
3437cdf0c1d5Smjnelson	fi
3438cdf0c1d5Smjnelson
3439daaffb31Sdp	print "</blockquote>"
34407c478bd9Sstevel@tonic-gatedone
34417c478bd9Sstevel@tonic-gate
3442daaffb31Sdpprint
3443daaffb31Sdpprint
3444cac38512Smjnelsonprint "<hr></hr>"
3445daaffb31Sdpprint "<p style=\"font-size: small\">"
34469a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3447daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3448daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3449e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3450daaffb31Sdpprint "</body>"
3451daaffb31Sdpprint "</html>"
34527c478bd9Sstevel@tonic-gate
34537c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
34547c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
34557c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
34567c478bd9Sstevel@tonic-gate
3457daaffb31Sdpprint "Done."
345802d26c39SVladimir Kotal
3459b0088928SVladimir Kotal#
3460ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3461b0088928SVladimir Kotal#
3462ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3463b0088928SVladimir Kotal	delete_webrev 1 1
3464ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3465ba44d8a2SVladimir Kotalfi
3466ba44d8a2SVladimir Kotal
346702d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
346802d26c39SVladimir Kotal	upload_webrev
346902d26c39SVladimir Kotal	exit $?
347002d26c39SVladimir Kotalfi
3471