xref: /titanic_52/usr/src/tools/scripts/webrev.sh (revision 8b3b7b16b716013336a6bcd4e09ee4d431aa6413)
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#
514daaffb31Sdp# input_cmd | bug2url | output_cmd
515daaffb31Sdp#
516daaffb31Sdp# Scan for bugids and insert <a> links to the relevent bug database.
517daaffb31Sdp#
518daaffb31Sdpbug2url()
5197c478bd9Sstevel@tonic-gate{
520b0088928SVladimir Kotal	$SED -e 's|[0-9]\{5,\}|<a href=\"'$BUGURL'&\">&</a>|g'
521daaffb31Sdp}
522daaffb31Sdp
5237c478bd9Sstevel@tonic-gate#
524daaffb31Sdp# input_cmd | sac2url | output_cmd
5257c478bd9Sstevel@tonic-gate#
526daaffb31Sdp# Scan for ARC cases and insert <a> links to the relevent SAC database.
527daaffb31Sdp# This is slightly complicated because inside the SWAN, SAC cases are
528daaffb31Sdp# grouped by ARC: PSARC/2006/123.  But on OpenSolaris.org, they are
529daaffb31Sdp# referenced as 2006/123 (without labelling the ARC).
5307c478bd9Sstevel@tonic-gate#
531daaffb31Sdpsac2url()
532daaffb31Sdp{
533e0e0293aSjmcp	if [[ -z "$Oflag" ]]; then
534b0088928SVladimir Kotal	    $SED -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\1/\2/\3\">\1 \2/\3</a>|g'
535daaffb31Sdp	else
536b0088928SVladimir Kotal	    $SED -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}\)/\([0-9]\{3\}\)|<a href=\"'$SACURL'/\2/\3\">\1 \2/\3</a>|g'
537daaffb31Sdp	fi
538daaffb31Sdp}
539daaffb31Sdp
5407c478bd9Sstevel@tonic-gate#
541daaffb31Sdp# strip_unchanged <infile> | output_cmd
5427c478bd9Sstevel@tonic-gate#
543daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
544daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
5457c478bd9Sstevel@tonic-gate#
546daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
547daaffb31Sdp# identical lines are retained before and after the changed lines to
548daaffb31Sdp# provide some context.  The number of these lines is controlled by the
549cdf0c1d5Smjnelson# variable C in the $AWK script below.
550daaffb31Sdp#
551daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
552daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
553daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
554daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
555daaffb31Sdp#
556daaffb31Sdpstrip_unchanged()
557daaffb31Sdp{
558cdf0c1d5Smjnelson	$AWK '
559daaffb31Sdp	BEGIN	{ C = c = 20 }
560cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
561daaffb31Sdp		if (c > C) {
562daaffb31Sdp			c -= C
563daaffb31Sdp			inx = 0
564daaffb31Sdp			if (c > C) {
565cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
566daaffb31Sdp				inx = c % C
567daaffb31Sdp				c = C
568daaffb31Sdp			}
569daaffb31Sdp
570daaffb31Sdp			for (i = 0; i < c; i++)
571daaffb31Sdp				print ln[(inx + i) % C]
572daaffb31Sdp		}
573daaffb31Sdp		c = 0;
574daaffb31Sdp		print
575daaffb31Sdp		next
576daaffb31Sdp	}
577daaffb31Sdp	{	if (c >= C) {
578daaffb31Sdp			ln[c % C] = $0
579daaffb31Sdp			c++;
580daaffb31Sdp			next;
581daaffb31Sdp		}
582daaffb31Sdp		c++;
583daaffb31Sdp		print
584daaffb31Sdp	}
585cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
586daaffb31Sdp
587daaffb31Sdp	' $1
588daaffb31Sdp}
589daaffb31Sdp
590daaffb31Sdp#
591daaffb31Sdp# sdiff_to_html
592daaffb31Sdp#
593daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
594daaffb31Sdp# processes the diff output to present the files as an HTML document with
595daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
596daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
597daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
598daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
599daaffb31Sdp# e.g.
600daaffb31Sdp#
601daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
602daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
603daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
604daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
605daaffb31Sdp#          1234567</a> my bugid' > <file>.html
606daaffb31Sdp#
607daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
608daaffb31Sdp# in the webrev tree.
609daaffb31Sdp#
610daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
611daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
612daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
613daaffb31Sdp# the editing codes, e.g.
6147c478bd9Sstevel@tonic-gate#
6157c478bd9Sstevel@tonic-gate#      8c8
6167c478bd9Sstevel@tonic-gate#      57a61
6177c478bd9Sstevel@tonic-gate#      63c66,76
6187c478bd9Sstevel@tonic-gate#      68,93d80
6197c478bd9Sstevel@tonic-gate#      106d90
6207c478bd9Sstevel@tonic-gate#      108,110d91
6217c478bd9Sstevel@tonic-gate#
622daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
623daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
624daaffb31Sdp#  into something like this:
6257c478bd9Sstevel@tonic-gate#
6267c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6277c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
628daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6297c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6307c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6317c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6327c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6337c478bd9Sstevel@tonic-gate#        :               :
6347c478bd9Sstevel@tonic-gate#
635daaffb31Sdp#  This script is then run on the original source file to generate the
636daaffb31Sdp#  HTML that corresponds to the source file.
6377c478bd9Sstevel@tonic-gate#
638daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
639daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
640daaffb31Sdp#  notice that the changes are color-coded:
6417c478bd9Sstevel@tonic-gate#
6427c478bd9Sstevel@tonic-gate#   black     - unchanged lines
6437c478bd9Sstevel@tonic-gate#   blue      - changed lines
6447c478bd9Sstevel@tonic-gate#   bold blue - new lines
6457c478bd9Sstevel@tonic-gate#   brown     - deleted lines
6467c478bd9Sstevel@tonic-gate#
647daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
648daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
649daaffb31Sdp#  Teamware's filemerge tool.
650daaffb31Sdp#
651daaffb31Sdpsdiff_to_html()
652daaffb31Sdp{
6537c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
6547c478bd9Sstevel@tonic-gate
655daaffb31Sdp	TNAME=$3
656daaffb31Sdp	TPATH=$4
657daaffb31Sdp	COMMENT=$5
658daaffb31Sdp
6597c478bd9Sstevel@tonic-gate	#
6607c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
6617c478bd9Sstevel@tonic-gate	#
662cdf0c1d5Smjnelson	$AWK '
6637c478bd9Sstevel@tonic-gate	BEGIN	{
6647c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
665daaffb31Sdp		printf "function removed() "
666daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
667daaffb31Sdp		printf "function changed() "
668daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
669daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6707c478bd9Sstevel@tonic-gate}
6717c478bd9Sstevel@tonic-gate	/^</	{next}
6727c478bd9Sstevel@tonic-gate	/^>/	{next}
6737c478bd9Sstevel@tonic-gate	/^---/	{next}
674daaffb31Sdp
6757c478bd9Sstevel@tonic-gate	{
6767c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6777c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
6787c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
6797c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
6807c478bd9Sstevel@tonic-gate			if (n == 1)
6817c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6827c478bd9Sstevel@tonic-gate			else
6837c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6847c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
6857c478bd9Sstevel@tonic-gate			next
6867c478bd9Sstevel@tonic-gate		}
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6897c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
6907c478bd9Sstevel@tonic-gate		s = r[1];
6917c478bd9Sstevel@tonic-gate		if (n == 1)
6927c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6937c478bd9Sstevel@tonic-gate		else {
6947c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
6957c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6967c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
6977c478bd9Sstevel@tonic-gate		}
6987c478bd9Sstevel@tonic-gate		next
6997c478bd9Sstevel@tonic-gate	}
7007c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7017c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7027c478bd9Sstevel@tonic-gate		n1 = r[1]
7037c478bd9Sstevel@tonic-gate		n2 = r[2]
7047c478bd9Sstevel@tonic-gate		if (n == 1)
705daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
7067c478bd9Sstevel@tonic-gate		else
707daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
7087c478bd9Sstevel@tonic-gate		next
7097c478bd9Sstevel@tonic-gate	}
7107c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7117c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7127c478bd9Sstevel@tonic-gate		n1 = r[1]
7137c478bd9Sstevel@tonic-gate		n2 = r[2]
7147c478bd9Sstevel@tonic-gate		final = n2
7157c478bd9Sstevel@tonic-gate		d1 = 0
7167c478bd9Sstevel@tonic-gate		if (n == 1)
717daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7187c478bd9Sstevel@tonic-gate		else {
7197c478bd9Sstevel@tonic-gate			d1 = n2 - n1
720daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7217c478bd9Sstevel@tonic-gate		}
7227c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7237c478bd9Sstevel@tonic-gate		n1 = r[1]
7247c478bd9Sstevel@tonic-gate		n2 = r[2]
7257c478bd9Sstevel@tonic-gate		if (m > 1) {
7267c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7277c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7287c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7297c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7307c478bd9Sstevel@tonic-gate			}
7317c478bd9Sstevel@tonic-gate		}
7327c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7337c478bd9Sstevel@tonic-gate
7347c478bd9Sstevel@tonic-gate		next
7357c478bd9Sstevel@tonic-gate	}
7367c478bd9Sstevel@tonic-gate	}
7377c478bd9Sstevel@tonic-gate
738daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
739daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7407c478bd9Sstevel@tonic-gate
7417c478bd9Sstevel@tonic-gate	#
7427c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
7437c478bd9Sstevel@tonic-gate	#
744cdf0c1d5Smjnelson	$AWK '
7457c478bd9Sstevel@tonic-gate	BEGIN	{
7467c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
747daaffb31Sdp		printf "function new() "
748daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
749daaffb31Sdp		printf "function changed() "
750daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
751daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7527c478bd9Sstevel@tonic-gate	}
753daaffb31Sdp
7547c478bd9Sstevel@tonic-gate	/^</	{next}
7557c478bd9Sstevel@tonic-gate	/^>/	{next}
7567c478bd9Sstevel@tonic-gate	/^---/	{next}
757daaffb31Sdp
7587c478bd9Sstevel@tonic-gate	{
7597c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7607c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7617c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
7627c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
7637c478bd9Sstevel@tonic-gate			if (n == 1)
7647c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7657c478bd9Sstevel@tonic-gate			else
7667c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7677c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7687c478bd9Sstevel@tonic-gate			next
7697c478bd9Sstevel@tonic-gate		}
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7727c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7737c478bd9Sstevel@tonic-gate		s = r[1];
7747c478bd9Sstevel@tonic-gate		if (n == 1)
7757c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7767c478bd9Sstevel@tonic-gate		else {
7777c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7787c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7797c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7807c478bd9Sstevel@tonic-gate		}
7817c478bd9Sstevel@tonic-gate		next
7827c478bd9Sstevel@tonic-gate	}
7837c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7847c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7857c478bd9Sstevel@tonic-gate		n1 = r[1]
7867c478bd9Sstevel@tonic-gate		n2 = r[2]
7877c478bd9Sstevel@tonic-gate		if (n == 1)
788daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7897c478bd9Sstevel@tonic-gate		else
790daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7917c478bd9Sstevel@tonic-gate		next
7927c478bd9Sstevel@tonic-gate	}
7937c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7947c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7957c478bd9Sstevel@tonic-gate		n1 = r[1]
7967c478bd9Sstevel@tonic-gate		n2 = r[2]
7977c478bd9Sstevel@tonic-gate		final = n2
7987c478bd9Sstevel@tonic-gate		d2 = 0;
7997c478bd9Sstevel@tonic-gate		if (n == 1) {
8007c478bd9Sstevel@tonic-gate			final = n1
801daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
8027c478bd9Sstevel@tonic-gate		} else {
8037c478bd9Sstevel@tonic-gate			d2 = n2 - n1
804daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
8057c478bd9Sstevel@tonic-gate		}
8067c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
8077c478bd9Sstevel@tonic-gate		n1 = r[1]
8087c478bd9Sstevel@tonic-gate		n2 = r[2]
8097c478bd9Sstevel@tonic-gate		if (m > 1) {
8107c478bd9Sstevel@tonic-gate			d1  = n2 - n1
8117c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8127c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8137c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8147c478bd9Sstevel@tonic-gate			}
8157c478bd9Sstevel@tonic-gate		}
8167c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8177c478bd9Sstevel@tonic-gate		next
8187c478bd9Sstevel@tonic-gate	}
8197c478bd9Sstevel@tonic-gate	}
820daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8217c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8227c478bd9Sstevel@tonic-gate
823daaffb31Sdp	#
824cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
825daaffb31Sdp	#
826cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8277c478bd9Sstevel@tonic-gate
828cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8297c478bd9Sstevel@tonic-gate
830daaffb31Sdp	#
831daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
832daaffb31Sdp	#
833daaffb31Sdp	print "$HTML<head>$STDHEAD"
834cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
835daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
836daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
837daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
838daaffb31Sdp	print "<table><tr valign=\"top\">"
839daaffb31Sdp	print "<td><pre>"
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
8427c478bd9Sstevel@tonic-gate
843daaffb31Sdp	print "</pre></td><td><pre>"
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
8467c478bd9Sstevel@tonic-gate
847daaffb31Sdp	print "</pre></td>"
848daaffb31Sdp	print "</tr></table>"
849daaffb31Sdp	print "</body></html>"
8507c478bd9Sstevel@tonic-gate
851daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
852daaffb31Sdp	    "$COMMENT"
8537c478bd9Sstevel@tonic-gate}
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate
856daaffb31Sdp#
857daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
858daaffb31Sdp#
859daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
860daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
861daaffb31Sdp# and then emit the main frame.  Content is placed into:
862daaffb31Sdp#
863daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
864daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
865daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
866daaffb31Sdp#
867daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
868daaffb31Sdp#
8697c478bd9Sstevel@tonic-gatefunction framed_sdiff
8707c478bd9Sstevel@tonic-gate{
8717c478bd9Sstevel@tonic-gate	typeset TNAME=$1
872daaffb31Sdp	typeset TPATH=$2
873daaffb31Sdp	typeset lhsfile=$3
874daaffb31Sdp	typeset rhsfile=$4
875daaffb31Sdp	typeset comments=$5
8767c478bd9Sstevel@tonic-gate	typeset RTOP
877daaffb31Sdp
8787c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
879daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
880daaffb31Sdp
881daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
882daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
883daaffb31Sdp
884daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
885*8b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8867c478bd9Sstevel@tonic-gate	    </head>
887daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
888cac38512Smjnelson	    <a name="0"></a>
889cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
890daaffb31Sdp	EOF
891daaffb31Sdp
892daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
893daaffb31Sdp
894daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
895daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
896daaffb31Sdp
897daaffb31Sdp	close='</body></html>'
898daaffb31Sdp
899daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
900daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
901daaffb31Sdp
902daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
903daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
904daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
905daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
906daaffb31Sdp	  <frameset rows="*,60">
907daaffb31Sdp	    <frameset cols="50%,50%">
908cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
909cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
910daaffb31Sdp	    </frameset>
911*8b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
912cac38512Smjnelson	   marginheight="0" name="nav"></frame>
913daaffb31Sdp	  <noframes>
914daaffb31Sdp            <body id="SUNWwebrev">
915daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9167c478bd9Sstevel@tonic-gate	      and has the feature enabled.
917daaffb31Sdp            </body>
918daaffb31Sdp	  </noframes>
919daaffb31Sdp	  </frameset>
9207c478bd9Sstevel@tonic-gate	</html>
9217c478bd9Sstevel@tonic-gate	EOF
9227c478bd9Sstevel@tonic-gate}
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate
925daaffb31Sdp#
926daaffb31Sdp# fix_postscript
927daaffb31Sdp#
928daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
929daaffb31Sdp# 	- removing all extraneous headers/trailers
930daaffb31Sdp#	- making the page numbers right
931daaffb31Sdp#	- removing pages devoid of contents which confuse some
932daaffb31Sdp#	  postscript readers.
933daaffb31Sdp#
934daaffb31Sdp# From Casper.
935daaffb31Sdp#
936daaffb31Sdpfunction fix_postscript
9377c478bd9Sstevel@tonic-gate{
938daaffb31Sdp	infile=$1
9397c478bd9Sstevel@tonic-gate
940daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9417c478bd9Sstevel@tonic-gate
942daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
943daaffb31Sdp	print "%%Orientation: Landscape\n";
9447c478bd9Sstevel@tonic-gate
945daaffb31Sdp	$pno = 0;
946daaffb31Sdp	$doprint = 1;
947daaffb31Sdp
948daaffb31Sdp	$page = "";
949daaffb31Sdp
950daaffb31Sdp	while (<>) {
951daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
952daaffb31Sdp
953daaffb31Sdp		if (/^%%Page:/) {
954daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
955daaffb31Sdp				# Header or single page containing text
956daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
957daaffb31Sdp				print $page;
958daaffb31Sdp				$pno++;
959daaffb31Sdp			} else {
960daaffb31Sdp				# Empty page, skip it.
9617c478bd9Sstevel@tonic-gate			}
962daaffb31Sdp			$page = "";
963daaffb31Sdp			$doprint = 1;
9647c478bd9Sstevel@tonic-gate			next;
9657c478bd9Sstevel@tonic-gate		}
9667c478bd9Sstevel@tonic-gate
967daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
968daaffb31Sdp		# %%Page of the next
969daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
970daaffb31Sdp		$page .= $_ if ($doprint);
9717c478bd9Sstevel@tonic-gate	}
9727c478bd9Sstevel@tonic-gate
973daaffb31Sdp	if ($page =~ /\)S/) {
974daaffb31Sdp		print "%%Page: ? $pno\n";
975daaffb31Sdp		print $page;
976daaffb31Sdp	} else {
977daaffb31Sdp		$pno--;
978daaffb31Sdp	}
979daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
980daaffb31SdpEOF
981daaffb31Sdp
98214983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
983daaffb31Sdp}
984daaffb31Sdp
985daaffb31Sdp
986daaffb31Sdp#
987daaffb31Sdp# input_cmd | insert_anchors | output_cmd
988daaffb31Sdp#
9897c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
990daaffb31Sdp# anchors.  These are used to drive the frames version of the
9917c478bd9Sstevel@tonic-gate# sdiffs output.
9927c478bd9Sstevel@tonic-gate#
9937c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9947c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9957c478bd9Sstevel@tonic-gate#
996daaffb31Sdp# The script detects changed lines as any line that has a "<span
997daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
998daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
9997c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
10007c478bd9Sstevel@tonic-gate# deleted.
10017c478bd9Sstevel@tonic-gate#
1002daaffb31Sdpfunction insert_anchors
1003daaffb31Sdp{
1004cdf0c1d5Smjnelson	$AWK '
10057c478bd9Sstevel@tonic-gate	function ia() {
1006daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
10077c478bd9Sstevel@tonic-gate	}
1008daaffb31Sdp
10097c478bd9Sstevel@tonic-gate	BEGIN {
1010daaffb31Sdp		anc=1;
10117c478bd9Sstevel@tonic-gate		inblock=1;
1012daaffb31Sdp		printf "<pre>\n";
10137c478bd9Sstevel@tonic-gate	}
1014daaffb31Sdp	NF == 0 || /^<span class=/ {
10157c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10167c478bd9Sstevel@tonic-gate			ia();
10177c478bd9Sstevel@tonic-gate			inblock=1;
10187c478bd9Sstevel@tonic-gate		}
10197c478bd9Sstevel@tonic-gate		print;
10207c478bd9Sstevel@tonic-gate		next;
10217c478bd9Sstevel@tonic-gate	}
10227c478bd9Sstevel@tonic-gate	{
10237c478bd9Sstevel@tonic-gate		inblock=0;
10247c478bd9Sstevel@tonic-gate		print;
10257c478bd9Sstevel@tonic-gate	}
10267c478bd9Sstevel@tonic-gate	END {
10277c478bd9Sstevel@tonic-gate		ia();
1028daaffb31Sdp
1029daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1030daaffb31Sdp		printf "--- EOF ---</b>"
10317c478bd9Sstevel@tonic-gate        	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1032daaffb31Sdp		printf "</pre>"
1033daaffb31Sdp		printf "<form name=\"eof\">";
1034cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1035cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1036daaffb31Sdp		printf "</form>";
10377c478bd9Sstevel@tonic-gate	}
10387c478bd9Sstevel@tonic-gate	' $1
10397c478bd9Sstevel@tonic-gate}
10407c478bd9Sstevel@tonic-gate
10417c478bd9Sstevel@tonic-gate
1042daaffb31Sdp#
1043daaffb31Sdp# relative_dir
1044daaffb31Sdp#
1045daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1046daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1047daaffb31Sdp# this function would print "../../../../".
1048daaffb31Sdp#
1049daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1050daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1051daaffb31Sdp# is not relocatable.
1052daaffb31Sdp#
1053daaffb31Sdpfunction relative_dir
10547c478bd9Sstevel@tonic-gate{
1055daaffb31Sdp        typeset cur="${1##$2?(/)}"
1056*8b3b7b16SMark J. Nelson
1057*8b3b7b16SMark J. Nelson        #
1058*8b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
1059*8b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
1060*8b3b7b16SMark J. Nelson        #
1061*8b3b7b16SMark J. Nelson        if [[ $1 =~ '^/.+' && "$cur" == "$1" ]]; then
1062daaffb31Sdp                # Should never happen.
106314983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1064daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1065daaffb31Sdp                print -u2 "will not be relocatable!"
1066daaffb31Sdp                print $2
1067daaffb31Sdp                return
1068daaffb31Sdp        fi
1069daaffb31Sdp
1070*8b3b7b16SMark J. Nelson	#
1071*8b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
1072*8b3b7b16SMark J. Nelson	#
1073*8b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
1074*8b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
1075*8b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
1076*8b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
1077*8b3b7b16SMark J. Nelson	#    the end of a relative path.
1078*8b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
1079*8b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
1080*8b3b7b16SMark J. Nelson	#    level of relative separation.
1081*8b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
1082*8b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
1083*8b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
1084*8b3b7b16SMark J. Nelson	#
1085*8b3b7b16SMark J. Nelson	print $(print $cur | $SED -e '{
1086*8b3b7b16SMark J. Nelson			s:^\./*::
1087*8b3b7b16SMark J. Nelson			s:/$::
1088*8b3b7b16SMark J. Nelson			s:[^/][^/]*:..:g
1089*8b3b7b16SMark J. Nelson		}' -e 's:^\(..*\)$:\1/:')
10907c478bd9Sstevel@tonic-gate}
10917c478bd9Sstevel@tonic-gate
1092daaffb31Sdp#
1093daaffb31Sdp# frame_nav_js
1094daaffb31Sdp#
1095daaffb31Sdp# Emit javascript for frame navigation
1096daaffb31Sdp#
1097daaffb31Sdpfunction frame_nav_js
10987c478bd9Sstevel@tonic-gate{
10997c478bd9Sstevel@tonic-gatecat << \EOF
11007c478bd9Sstevel@tonic-gatevar myInt;
11017c478bd9Sstevel@tonic-gatevar scrolling=0;
1102daaffb31Sdpvar sfactor = 3;
11037c478bd9Sstevel@tonic-gatevar scount=10;
11047c478bd9Sstevel@tonic-gate
11057c478bd9Sstevel@tonic-gatefunction scrollByPix() {
11067c478bd9Sstevel@tonic-gate	if (scount<=0) {
11077c478bd9Sstevel@tonic-gate		sfactor*=1.2;
11087c478bd9Sstevel@tonic-gate		scount=10;
11097c478bd9Sstevel@tonic-gate	}
11107c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11117c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11127c478bd9Sstevel@tonic-gate	scount--;
11137c478bd9Sstevel@tonic-gate}
11147c478bd9Sstevel@tonic-gate
1115daaffb31Sdpfunction scrollToAnc(num) {
1116daaffb31Sdp
1117daaffb31Sdp	// Update the value of the anchor in the form which we use as
1118daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1119daaffb31Sdp	// correcting for overflow and underflow of the value and return
1120daaffb31Sdp	// us the new value.
1121daaffb31Sdp	num = setAncValue(num);
1122daaffb31Sdp
1123daaffb31Sdp	// Set location and scroll back a little to expose previous
1124daaffb31Sdp	// lines.
1125daaffb31Sdp	//
1126daaffb31Sdp	// Note that this could be improved: it is possible although
1127daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1128daaffb31Sdp	// scroll to that location directly.
1129daaffb31Sdp	//
11307c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11317c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1132daaffb31Sdp
11337c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11347c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11357c478bd9Sstevel@tonic-gate}
11367c478bd9Sstevel@tonic-gate
1137daaffb31Sdpfunction getAncValue()
1138daaffb31Sdp{
1139daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1140daaffb31Sdp}
1141daaffb31Sdp
1142daaffb31Sdpfunction setAncValue(val)
1143daaffb31Sdp{
1144daaffb31Sdp	if (val <= 0) {
1145daaffb31Sdp		val = 0;
1146daaffb31Sdp		parent.nav.document.diff.real.value = val;
1147daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1148daaffb31Sdp		return (val);
1149daaffb31Sdp	}
1150daaffb31Sdp
1151daaffb31Sdp	//
1152daaffb31Sdp	// The way we compute the max anchor value is to stash it
1153daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1154daaffb31Sdp	// on each side, so we pluck from the left.
1155daaffb31Sdp	//
1156daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1157daaffb31Sdp	if (val < maxval) {
1158daaffb31Sdp		parent.nav.document.diff.real.value = val;
1159daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1160daaffb31Sdp		return (val);
1161daaffb31Sdp	}
1162daaffb31Sdp
1163daaffb31Sdp	// this must be: val >= maxval
1164daaffb31Sdp	val = maxval;
1165daaffb31Sdp	parent.nav.document.diff.real.value = val;
1166daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1167daaffb31Sdp	return (val);
1168daaffb31Sdp}
1169daaffb31Sdp
11707c478bd9Sstevel@tonic-gatefunction stopScroll() {
11717c478bd9Sstevel@tonic-gate	if (scrolling==1) {
11727c478bd9Sstevel@tonic-gate		clearInterval(myInt);
11737c478bd9Sstevel@tonic-gate		scrolling=0;
11747c478bd9Sstevel@tonic-gate	}
11757c478bd9Sstevel@tonic-gate}
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gatefunction startScroll() {
11787c478bd9Sstevel@tonic-gate	stopScroll();
11797c478bd9Sstevel@tonic-gate	scrolling=1;
11807c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11817c478bd9Sstevel@tonic-gate}
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1184daaffb31Sdp
11857c478bd9Sstevel@tonic-gate	switch (b) {
11867c478bd9Sstevel@tonic-gate	    case 1 :
1187daaffb31Sdp		scrollToAnc(-1);
11887c478bd9Sstevel@tonic-gate		break;
11897c478bd9Sstevel@tonic-gate	    case 2 :
1190daaffb31Sdp		scrollToAnc(getAncValue() - 1);
11917c478bd9Sstevel@tonic-gate		break;
11927c478bd9Sstevel@tonic-gate	    case 3 :
11937c478bd9Sstevel@tonic-gate		sfactor=-3;
11947c478bd9Sstevel@tonic-gate		startScroll();
11957c478bd9Sstevel@tonic-gate		break;
11967c478bd9Sstevel@tonic-gate	    case 4 :
11977c478bd9Sstevel@tonic-gate		sfactor=3;
11987c478bd9Sstevel@tonic-gate		startScroll();
11997c478bd9Sstevel@tonic-gate		break;
12007c478bd9Sstevel@tonic-gate	    case 5 :
1201daaffb31Sdp		scrollToAnc(getAncValue() + 1);
12027c478bd9Sstevel@tonic-gate		break;
12037c478bd9Sstevel@tonic-gate	    case 6 :
1204daaffb31Sdp		scrollToAnc(999999);
12057c478bd9Sstevel@tonic-gate		break;
12067c478bd9Sstevel@tonic-gate	}
12077c478bd9Sstevel@tonic-gate}
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
12107c478bd9Sstevel@tonic-gate	stopScroll();
12117c478bd9Sstevel@tonic-gate}
12127c478bd9Sstevel@tonic-gate
1213daaffb31Sdpfunction keypress(ev) {
1214daaffb31Sdp	var keynum;
1215daaffb31Sdp	var keychar;
1216daaffb31Sdp
1217daaffb31Sdp	if (window.event) { // IE
1218daaffb31Sdp		keynum = ev.keyCode;
1219daaffb31Sdp	} else if (ev.which) { // non-IE
1220daaffb31Sdp		keynum = ev.which;
1221daaffb31Sdp	}
1222daaffb31Sdp
1223daaffb31Sdp	keychar = String.fromCharCode(keynum);
1224daaffb31Sdp
1225daaffb31Sdp	if (keychar == "k") {
1226daaffb31Sdp		handlePress(2);
1227daaffb31Sdp		return (0);
1228daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1229daaffb31Sdp		handlePress(5);
1230daaffb31Sdp		return (0);
1231daaffb31Sdp	}
1232daaffb31Sdp	return (1);
1233daaffb31Sdp}
1234daaffb31Sdp
12357c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1236daaffb31Sdp	val = parent.nav.document.diff.display.value;
1237daaffb31Sdp	if (val == "EOF") {
1238daaffb31Sdp		scrollToAnc(999999);
1239daaffb31Sdp		return;
1240daaffb31Sdp	}
1241daaffb31Sdp
1242daaffb31Sdp	if (val == "BOF") {
1243daaffb31Sdp		scrollToAnc(0);
1244daaffb31Sdp		return;
1245daaffb31Sdp	}
1246daaffb31Sdp
1247daaffb31Sdp        i=parseInt(val);
12487c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1249daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
12507c478bd9Sstevel@tonic-gate        } else {
1251daaffb31Sdp                scrollToAnc(i);
12527c478bd9Sstevel@tonic-gate        }
12537c478bd9Sstevel@tonic-gate        return false;
12547c478bd9Sstevel@tonic-gate}
12557c478bd9Sstevel@tonic-gate
1256daaffb31SdpEOF
1257daaffb31Sdp}
1258daaffb31Sdp
1259daaffb31Sdp#
1260daaffb31Sdp# frame_navigation
1261daaffb31Sdp#
1262daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1263daaffb31Sdp#
1264daaffb31Sdpfunction frame_navigation
1265daaffb31Sdp{
1266daaffb31Sdp	print "$HTML<head>$STDHEAD"
1267daaffb31Sdp
1268daaffb31Sdp	cat << \EOF
1269daaffb31Sdp<title>Anchor Navigation</title>
1270daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1271daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1272daaffb31Sdp
1273daaffb31Sdp<style type="text/css">
1274daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1275daaffb31Sdp		    background-color: #eee; text-align: center;
1276daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1277daaffb31Sdp    div.button a { font-weight: bold; color: black }
1278daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1279daaffb31Sdp</style>
1280daaffb31SdpEOF
1281daaffb31Sdp
1282cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1283daaffb31Sdp
1284daaffb31Sdp	cat << \EOF
12857c478bd9Sstevel@tonic-gate</head>
1286daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1287daaffb31Sdp	onkeypress="keypress(event);">
12887c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
12897c478bd9Sstevel@tonic-gate      <center>
1290cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12917c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12927c478bd9Sstevel@tonic-gate      </center>
12937c478bd9Sstevel@tonic-gate    </noscript>
12947c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1295daaffb31Sdp	<tr>
1296daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1297daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1298daaffb31Sdp          at right</td>
1299daaffb31Sdp	  <td align="center" valign="top" width="50%">
13007c478bd9Sstevel@tonic-gate	    <div class="button">
1301daaffb31Sdp	      <table border="0" align="center">
1302daaffb31Sdp                  <tr>
1303daaffb31Sdp		    <td>
13047c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
13057c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
13067c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
13077c478bd9Sstevel@tonic-gate			 onClick="return false;"
13087c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1309daaffb31Sdp		    <td>
13107c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13117c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13127c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13137c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1314daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1315daaffb31Sdp		    <td>
13167c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13177c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13187c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13197c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13207c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13217c478bd9Sstevel@tonic-gate		    </td></tr>
1322daaffb31Sdp
13237c478bd9Sstevel@tonic-gate		  <tr>
1324daaffb31Sdp		    <td>
13257c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13267c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13277c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13287c478bd9Sstevel@tonic-gate			 onClick="return false;"
13297c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1330daaffb31Sdp		    <td>
13317c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13327c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13337c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13347c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1335daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1336daaffb31Sdp		    <td>
13377c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13387c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13397c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13407c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
13417c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1342daaffb31Sdp		  </tr>
1343daaffb31Sdp              </table>
1344daaffb31Sdp	    </div>
1345daaffb31Sdp	  </td>
13467c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1347daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1348cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1349cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13507c478bd9Sstevel@tonic-gate	    </form>
13517c478bd9Sstevel@tonic-gate	  </th>
1352daaffb31Sdp	</tr>
13537c478bd9Sstevel@tonic-gate    </table>
13547c478bd9Sstevel@tonic-gate  </body>
13557c478bd9Sstevel@tonic-gate</html>
13567c478bd9Sstevel@tonic-gateEOF
13577c478bd9Sstevel@tonic-gate}
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate
1360daaffb31Sdp
1361daaffb31Sdp#
1362daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1363daaffb31Sdp#
1364daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1365daaffb31Sdp# context or unified diffs.
1366daaffb31Sdp#
13677c478bd9Sstevel@tonic-gatediff_to_html()
13687c478bd9Sstevel@tonic-gate{
13697c478bd9Sstevel@tonic-gate	TNAME=$1
1370daaffb31Sdp	TPATH=$2
1371daaffb31Sdp	DIFFTYPE=$3
1372daaffb31Sdp	COMMENT=$4
1373daaffb31Sdp
1374daaffb31Sdp	print "$HTML<head>$STDHEAD"
1375daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1376daaffb31Sdp
1377daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1378daaffb31Sdp		print "$UDIFFCSS"
1379daaffb31Sdp	fi
1380daaffb31Sdp
1381daaffb31Sdp	cat <<-EOF
1382daaffb31Sdp	</head>
1383daaffb31Sdp	<body id="SUNWwebrev">
1384daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1385daaffb31Sdp	<pre>$COMMENT</pre>
1386daaffb31Sdp        <pre>
1387daaffb31Sdp	EOF
13887c478bd9Sstevel@tonic-gate
1389cdf0c1d5Smjnelson	html_quote | $AWK '
1390daaffb31Sdp	/^--- new/	{ next }
1391daaffb31Sdp	/^\+\+\+ new/	{ next }
1392daaffb31Sdp	/^--- old/	{ next }
1393daaffb31Sdp	/^\*\*\* old/	{ next }
1394daaffb31Sdp	/^\*\*\*\*/	{ next }
13957c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1396cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1397daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1398daaffb31Sdp			  next}
1399daaffb31Sdp
1400cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1401daaffb31Sdp			  next}
1402daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1403daaffb31Sdp			  next}
1404daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1405daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1406daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1407daaffb31Sdp			{printf "%s\n", $0; next}
14087c478bd9Sstevel@tonic-gate	'
1409daaffb31Sdp
1410daaffb31Sdp	print "</pre></body></html>\n"
14117c478bd9Sstevel@tonic-gate}
14127c478bd9Sstevel@tonic-gate
14137c478bd9Sstevel@tonic-gate
1414daaffb31Sdp#
1415daaffb31Sdp# source_to_html { new | old } <filename>
1416daaffb31Sdp#
1417daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1418daaffb31Sdp#
14197c478bd9Sstevel@tonic-gatesource_to_html()
14207c478bd9Sstevel@tonic-gate{
14217c478bd9Sstevel@tonic-gate	WHICH=$1
14227c478bd9Sstevel@tonic-gate	TNAME=$2
14237c478bd9Sstevel@tonic-gate
1424daaffb31Sdp	print "$HTML<head>$STDHEAD"
1425cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1426daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1427daaffb31Sdp	print "<pre>"
1428cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1429daaffb31Sdp	print "</pre></body></html>"
14307c478bd9Sstevel@tonic-gate}
14317c478bd9Sstevel@tonic-gate
1432daaffb31Sdp#
1433cdf0c1d5Smjnelson# comments_from_teamware {text|html} parent-file child-file
1434daaffb31Sdp#
1435daaffb31Sdp# Find the first delta in the child that's not in the parent.  Get the
1436daaffb31Sdp# newest delta from the parent, get all deltas from the child starting
1437daaffb31Sdp# with that delta, and then get all info starting with the second oldest
1438daaffb31Sdp# delta in that list (the first delta unique to the child).
14397c478bd9Sstevel@tonic-gate#
14407c478bd9Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
1441daaffb31Sdp#
1442daaffb31Sdpcomments_from_teamware()
14437c478bd9Sstevel@tonic-gate{
1444daaffb31Sdp	fmt=$1
1445daaffb31Sdp	pfile=$PWS/$2
1446daaffb31Sdp	cfile=$CWS/$3
14477c478bd9Sstevel@tonic-gate
1448cdf0c1d5Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
1449cdf0c1d5Smjnelson		pfile=$RWS/$2
1450cdf0c1d5Smjnelson	fi
1451cdf0c1d5Smjnelson
1452daaffb31Sdp	if [[ -f $pfile ]]; then
1453cdf0c1d5Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14547c478bd9Sstevel@tonic-gate	else
14557c478bd9Sstevel@tonic-gate		psid=1.1
14567c478bd9Sstevel@tonic-gate	fi
14577c478bd9Sstevel@tonic-gate
1458cdf0c1d5Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14597c478bd9Sstevel@tonic-gate	N=${#sids[@]}
14607c478bd9Sstevel@tonic-gate
1461daaffb31Sdp	nawkprg='
1462daaffb31Sdp		/^COMMENTS:/	{p=1; continue}
1463daaffb31Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
1464daaffb31Sdp		NF == 0u	{ continue }
1465daaffb31Sdp		{if (p==0) continue; print $0 }'
1466daaffb31Sdp
14677c478bd9Sstevel@tonic-gate	if [[ $N -ge 2 ]]; then
14687c478bd9Sstevel@tonic-gate		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14697c478bd9Sstevel@tonic-gate
1470daaffb31Sdp		if [[ $fmt == "text" ]]; then
1471cdf0c1d5Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1472cdf0c1d5Smjnelson			    $AWK "$nawkprg"
1473daaffb31Sdp			return
1474daaffb31Sdp		fi
1475daaffb31Sdp
1476cdf0c1d5Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
1477cdf0c1d5Smjnelson		    html_quote | bug2url | sac2url | $AWK "$nawkprg"
14787c478bd9Sstevel@tonic-gate	fi
14797c478bd9Sstevel@tonic-gate}
14807c478bd9Sstevel@tonic-gate
1481daaffb31Sdp#
1482cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1483daaffb31Sdp#
1484cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1485cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1486cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1487cdf0c1d5Smjnelson# are turned into URLs.
1488cdf0c1d5Smjnelson#
1489cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1490daaffb31Sdp#
1491daaffb31Sdpcomments_from_wx()
14927c478bd9Sstevel@tonic-gate{
1493daaffb31Sdp	typeset fmt=$1
1494daaffb31Sdp	typeset p=$2
14957c478bd9Sstevel@tonic-gate
1496cdf0c1d5Smjnelson	comm=`$AWK '
1497daaffb31Sdp	$1 == "'$p'" {
14987c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
14997c478bd9Sstevel@tonic-gate		getline
15007c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
15017c478bd9Sstevel@tonic-gate		exit
1502daaffb31Sdp	}' < $wxfile`
1503daaffb31Sdp
1504cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1505cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1506cdf0c1d5Smjnelson	fi
1507cdf0c1d5Smjnelson
1508daaffb31Sdp	if [[ $fmt == "text" ]]; then
1509cdf0c1d5Smjnelson		print -- "$comm"
1510daaffb31Sdp		return
1511daaffb31Sdp	fi
1512daaffb31Sdp
1513cdf0c1d5Smjnelson	print -- "$comm" | html_quote | bug2url | sac2url
1514cdf0c1d5Smjnelson
15157c478bd9Sstevel@tonic-gate}
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate#
1518daaffb31Sdp# getcomments {text|html} filepath parentpath
1519daaffb31Sdp#
1520daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1521daaffb31Sdp#
1522daaffb31Sdpgetcomments()
1523daaffb31Sdp{
1524daaffb31Sdp	typeset fmt=$1
1525daaffb31Sdp	typeset p=$2
1526daaffb31Sdp	typeset pp=$3
15277c478bd9Sstevel@tonic-gate
15283df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15293df69ef3SDarren Moffat		return
15303df69ef3SDarren Moffat	fi
1531cdf0c1d5Smjnelson	#
1532cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1533cdf0c1d5Smjnelson	# will be used there, too
1534cdf0c1d5Smjnelson	#
1535daaffb31Sdp	if [[ -n $wxfile ]]; then
1536daaffb31Sdp		comments_from_wx $fmt $p
1537daaffb31Sdp	else
1538daaffb31Sdp		if [[ $SCM_MODE == "teamware" ]]; then
1539daaffb31Sdp			comments_from_teamware $fmt $pp $p
1540daaffb31Sdp		fi
1541daaffb31Sdp	fi
1542daaffb31Sdp}
1543daaffb31Sdp
1544daaffb31Sdp#
1545daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1546daaffb31Sdp#
1547daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1548daaffb31Sdp#
1549daaffb31Sdpfunction printCI
1550daaffb31Sdp{
1551daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1552daaffb31Sdp	typeset str
1553daaffb31Sdp	if (( tot == 1 )); then
1554daaffb31Sdp		str="line"
1555daaffb31Sdp	else
1556daaffb31Sdp		str="lines"
1557daaffb31Sdp	fi
1558daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1559daaffb31Sdp	    $tot $str $ins $del $mod $unc
1560daaffb31Sdp}
1561daaffb31Sdp
1562daaffb31Sdp
1563daaffb31Sdp#
1564daaffb31Sdp# difflines <oldfile> <newfile>
1565daaffb31Sdp#
1566daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1567daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1568daaffb31Sdp#
15697c478bd9Sstevel@tonic-gatefunction difflines
15707c478bd9Sstevel@tonic-gate{
1571daaffb31Sdp	integer tot mod del ins unc err
15727c478bd9Sstevel@tonic-gate	typeset filename
15737c478bd9Sstevel@tonic-gate
1574cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1575daaffb31Sdp	# Change range of lines: N,Nc
15767c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15777c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15787c478bd9Sstevel@tonic-gate		if (n != 2) {
15797c478bd9Sstevel@tonic-gate		    error=2
15807c478bd9Sstevel@tonic-gate		    exit;
15817c478bd9Sstevel@tonic-gate		}
1582daaffb31Sdp		#
1583daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1584daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1585daaffb31Sdp		#
15867c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1587daaffb31Sdp
1588daaffb31Sdp		#
1589daaffb31Sdp		# Now count replacement lines: each represents a change instead
1590daaffb31Sdp		# of a delete, so increment c and decrement r.
1591daaffb31Sdp		#
15927c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15937c478bd9Sstevel@tonic-gate			c++;
15947c478bd9Sstevel@tonic-gate			r--;
15957c478bd9Sstevel@tonic-gate		}
1596daaffb31Sdp		#
1597daaffb31Sdp		# If there were more replacement lines than original lines,
1598daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1599daaffb31Sdp		# but there are r changes that should be counted as adds, and
1600daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1601daaffb31Sdp		#
16027c478bd9Sstevel@tonic-gate		if (r < 0) {
16037c478bd9Sstevel@tonic-gate			a-=r;
16047c478bd9Sstevel@tonic-gate			c+=r;
16057c478bd9Sstevel@tonic-gate		}
1606daaffb31Sdp
1607daaffb31Sdp		#
1608daaffb31Sdp		# If there were more original lines than replacement lines, then
1609daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1610daaffb31Sdp		#
16117c478bd9Sstevel@tonic-gate		if (r > 0) {
16127c478bd9Sstevel@tonic-gate			d+=r;
16137c478bd9Sstevel@tonic-gate		}
16147c478bd9Sstevel@tonic-gate		next;
16157c478bd9Sstevel@tonic-gate	}
16167c478bd9Sstevel@tonic-gate
1617daaffb31Sdp	# Change lines: Nc
16187c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1619daaffb31Sdp		# The first line is a replacement; any more are additions.
16207c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16217c478bd9Sstevel@tonic-gate			c++;
16227c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16237c478bd9Sstevel@tonic-gate		}
16247c478bd9Sstevel@tonic-gate		next;
16257c478bd9Sstevel@tonic-gate	}
16267c478bd9Sstevel@tonic-gate
1627daaffb31Sdp	# Add lines: both Na and N,Na
16287c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16297c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16307c478bd9Sstevel@tonic-gate		next;
16317c478bd9Sstevel@tonic-gate	}
16327c478bd9Sstevel@tonic-gate
1633daaffb31Sdp	# Delete range of lines: N,Nd
16347c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16357c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16367c478bd9Sstevel@tonic-gate		if (n != 2) {
16377c478bd9Sstevel@tonic-gate			error=2
16387c478bd9Sstevel@tonic-gate			exit;
16397c478bd9Sstevel@tonic-gate		}
1640daaffb31Sdp		#
1641daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1642daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1643daaffb31Sdp		#
16447c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16457c478bd9Sstevel@tonic-gate		d+=r;
16467c478bd9Sstevel@tonic-gate		next;
16477c478bd9Sstevel@tonic-gate	}
16487c478bd9Sstevel@tonic-gate
1649daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16507c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16517c478bd9Sstevel@tonic-gate
1652daaffb31Sdp	# Should not get here!
16537c478bd9Sstevel@tonic-gate	{
16547c478bd9Sstevel@tonic-gate		error=1;
16557c478bd9Sstevel@tonic-gate		exit;
16567c478bd9Sstevel@tonic-gate	}
16577c478bd9Sstevel@tonic-gate
1658daaffb31Sdp	# Finish off - print results
16597c478bd9Sstevel@tonic-gate	END {
1660daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16617c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16627c478bd9Sstevel@tonic-gate	}' )
16637c478bd9Sstevel@tonic-gate
1664cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16657c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1666daaffb31Sdp		print "Unexpected Error occurred reading" \
1667daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1668daaffb31Sdp		return
1669daaffb31Sdp	fi
1670daaffb31Sdp
16717c478bd9Sstevel@tonic-gate	# Accumulate totals
16727c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1673daaffb31Sdp	(( TMOD += mod ))
16747c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16757c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16767c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1677cdf0c1d5Smjnelson	unc=`wc -l < $1`
16787c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1679daaffb31Sdp		(( unc -= del + mod ))
16807c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16817c478bd9Sstevel@tonic-gate	fi
16827c478bd9Sstevel@tonic-gate	# print summary
1683daaffb31Sdp	print "<span class=\"lineschanged\">"
1684daaffb31Sdp	printCI $tot $ins $del $mod $unc
1685daaffb31Sdp	print "</span>"
16867c478bd9Sstevel@tonic-gate}
16877c478bd9Sstevel@tonic-gate
1688daaffb31Sdp
16897c478bd9Sstevel@tonic-gate#
1690daaffb31Sdp# flist_from_wx
1691daaffb31Sdp#
1692daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1693daaffb31Sdp# Sets the global 'wxfile' variable.
1694daaffb31Sdp#
1695daaffb31Sdpfunction flist_from_wx
16967c478bd9Sstevel@tonic-gate{
1697daaffb31Sdp	typeset argfile=$1
1698daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1699daaffb31Sdp		#
1700daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1701daaffb31Sdp		# because the webrev does a "cd" later on.
1702daaffb31Sdp		#
1703daaffb31Sdp		wxfile=$PWD/$argfile
17047c478bd9Sstevel@tonic-gate	else
1705daaffb31Sdp		wxfile=$argfile
17067c478bd9Sstevel@tonic-gate	fi
17077c478bd9Sstevel@tonic-gate
1708cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
17097c478bd9Sstevel@tonic-gate	  while (getline) {
17107c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
17117c478bd9Sstevel@tonic-gate		if (c > 0) print
17127c478bd9Sstevel@tonic-gate	  }
1713daaffb31Sdp	}' $wxfile > $FLIST
17147c478bd9Sstevel@tonic-gate
1715daaffb31Sdp	print " Done."
1716daaffb31Sdp}
17177c478bd9Sstevel@tonic-gate
1718daaffb31Sdp#
1719daaffb31Sdp# flist_from_teamware [ <args-to-putback-n> ]
1720daaffb31Sdp#
1721daaffb31Sdp# Generate the file list by extracting file names from a putback -n.  Some
1722daaffb31Sdp# names may come from the "update/create" messages and others from the
1723daaffb31Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
1724daaffb31Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
1725daaffb31Sdp# -n as well, but remove them if they are already defined.
1726daaffb31Sdp#
1727daaffb31Sdpfunction flist_from_teamware
1728daaffb31Sdp{
1729cdf0c1d5Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
1730daaffb31Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
1731daaffb31Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
1732daaffb31Sdp			    "valid teamware workspace"
17337c478bd9Sstevel@tonic-gate			exit 1
17347c478bd9Sstevel@tonic-gate		fi
1735daaffb31Sdp		parent_args="-p $codemgr_parent"
17367c478bd9Sstevel@tonic-gate	fi
17377c478bd9Sstevel@tonic-gate
1738daaffb31Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17397c478bd9Sstevel@tonic-gate
1740daaffb31Sdp	putback -n $parent_args $* 2>&1 |
1741cdf0c1d5Smjnelson	    $AWK '
1742daaffb31Sdp		/^update:|^create:/	{print $2}
1743daaffb31Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
1744daaffb31Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
1745daaffb31Sdp		/^The following files are currently checked out/ {p = 1; continue}
1746daaffb31Sdp		NF == 0			{p=0 ; continue}
1747daaffb31Sdp		/^rename/		{old=$3}
1748daaffb31Sdp		$1 == "to:"		{print $2, old}
1749daaffb31Sdp		/^"/			{continue}
1750daaffb31Sdp		p == 1			{print $1}' |
1751daaffb31Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17527c478bd9Sstevel@tonic-gate
1753daaffb31Sdp	print " Done."
1754daaffb31Sdp}
1755daaffb31Sdp
1756cdf0c1d5Smjnelson#
1757cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1758cdf0c1d5Smjnelson#
1759cdf0c1d5Smjnelsonfunction hg_active_wxfile
1760cdf0c1d5Smjnelson{
1761cdf0c1d5Smjnelson	typeset child=$1
1762cdf0c1d5Smjnelson	typeset parent=$2
1763cdf0c1d5Smjnelson
1764cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17659a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1766cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1767cdf0c1d5Smjnelson}
1768cdf0c1d5Smjnelson
1769cdf0c1d5Smjnelson#
1770cdf0c1d5Smjnelson# flist_from_mercurial
1771cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1772cdf0c1d5Smjnelson# flist_from_wx
1773cdf0c1d5Smjnelson#
1774cdf0c1d5Smjnelsonfunction flist_from_mercurial
1775cdf0c1d5Smjnelson{
1776cdf0c1d5Smjnelson	typeset child=$1
1777cdf0c1d5Smjnelson	typeset parent=$2
1778cdf0c1d5Smjnelson
1779cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1780cdf0c1d5Smjnelson
1781cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1782cdf0c1d5Smjnelson		print		# Blank line for the \c above
1783cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1784cdf0c1d5Smjnelson		exit 1
1785cdf0c1d5Smjnelson	fi
1786cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1787cdf0c1d5Smjnelson
1788cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1789cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1790cdf0c1d5Smjnelson}
1791cdf0c1d5Smjnelson
1792cdf0c1d5Smjnelson#
1793cdf0c1d5Smjnelson# flist_from_subversion
1794cdf0c1d5Smjnelson#
1795cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1796cdf0c1d5Smjnelson#
1797cdf0c1d5Smjnelsonfunction flist_from_subversion
1798cdf0c1d5Smjnelson{
1799cdf0c1d5Smjnelson	CWS=$1
1800cdf0c1d5Smjnelson	OLDPWD=$2
1801cdf0c1d5Smjnelson
1802cdf0c1d5Smjnelson	cd $CWS
1803cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1804cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1805cdf0c1d5Smjnelson	print -u2 " Done."
1806cdf0c1d5Smjnelson	cd $OLDPWD
1807cdf0c1d5Smjnelson}
1808cdf0c1d5Smjnelson
1809daaffb31Sdpfunction env_from_flist
1810daaffb31Sdp{
1811daaffb31Sdp	[[ -r $FLIST ]] || return
1812daaffb31Sdp
1813daaffb31Sdp	#
1814daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1815daaffb31Sdp	# list.  Then copy those into our local versions of those
1816daaffb31Sdp	# variables if they have not been set already.
1817daaffb31Sdp	#
1818b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18197c478bd9Sstevel@tonic-gate
1820cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1821cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1822cdf0c1d5Smjnelson		export CODEMGR_WS
1823cdf0c1d5Smjnelson	fi
18247c478bd9Sstevel@tonic-gate
1825daaffb31Sdp	#
1826daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1827daaffb31Sdp	#
1828cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1829daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1830cdf0c1d5Smjnelson		export CODEMGR_PARENT
1831daaffb31Sdp	fi
1832daaffb31Sdp}
1833daaffb31Sdp
183414983201Sdpfunction look_for_prog
183514983201Sdp{
183614983201Sdp	typeset path
183714983201Sdp	typeset ppath
183814983201Sdp	typeset progname=$1
183914983201Sdp
184014983201Sdp	ppath=$PATH
184114983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
184214983201Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
1843cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
184414983201Sdp
184514983201Sdp	PATH=$ppath prog=`whence $progname`
184614983201Sdp	if [[ -n $prog ]]; then
184714983201Sdp		print $prog
184814983201Sdp	fi
184914983201Sdp}
185014983201Sdp
1851cdf0c1d5Smjnelsonfunction get_file_mode
1852cdf0c1d5Smjnelson{
1853cdf0c1d5Smjnelson	$PERL -e '
1854cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1855cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1856cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1857cdf0c1d5Smjnelson			exit 0;
1858cdf0c1d5Smjnelson		} else {
1859cdf0c1d5Smjnelson			exit 1;
1860cdf0c1d5Smjnelson		}
1861cdf0c1d5Smjnelson	    ' $1
1862cdf0c1d5Smjnelson}
1863cdf0c1d5Smjnelson
1864cdf0c1d5Smjnelsonfunction build_old_new_teamware
1865cdf0c1d5Smjnelson{
1866cdf0c1d5Smjnelson	typeset olddir="$1"
1867cdf0c1d5Smjnelson	typeset newdir="$2"
1868cdf0c1d5Smjnelson
1869cdf0c1d5Smjnelson	# If the child's version doesn't exist then
1870cdf0c1d5Smjnelson	# get a readonly copy.
1871cdf0c1d5Smjnelson
1872cdf0c1d5Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
1873cdf0c1d5Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
1874cdf0c1d5Smjnelson	fi
1875cdf0c1d5Smjnelson
1876cdf0c1d5Smjnelson	# The following two sections propagate file permissions the
1877cdf0c1d5Smjnelson	# same way SCCS does.  If the file is already under version
1878cdf0c1d5Smjnelson	# control, always use permissions from the SCCS/s.file.  If
1879cdf0c1d5Smjnelson	# the file is not under SCCS control, use permissions from the
1880cdf0c1d5Smjnelson	# working copy.  In all cases, the file copied to the webrev
1881cdf0c1d5Smjnelson	# is set to read only, and group/other permissions are set to
1882cdf0c1d5Smjnelson	# match those of the file owner.  This way, even if the file
1883cdf0c1d5Smjnelson	# is currently checked out, the webrev will display the final
1884cdf0c1d5Smjnelson	# permissions that would result after check in.
1885cdf0c1d5Smjnelson
1886cdf0c1d5Smjnelson	#
1887cdf0c1d5Smjnelson	# Snag new version of file.
1888cdf0c1d5Smjnelson	#
1889cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
1890cdf0c1d5Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
1891cdf0c1d5Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
1892cdf0c1d5Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
1893cdf0c1d5Smjnelson		    $newdir/$DIR/$F
1894cdf0c1d5Smjnelson	fi
1895cdf0c1d5Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
1896cdf0c1d5Smjnelson
1897cdf0c1d5Smjnelson	#
1898cdf0c1d5Smjnelson	# Get the parent's version of the file. First see whether the
1899cdf0c1d5Smjnelson	# child's version is checked out and get the parent's version
1900cdf0c1d5Smjnelson	# with keywords expanded or unexpanded as appropriate.
1901cdf0c1d5Smjnelson	#
1902cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
1903cdf0c1d5Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
1904cdf0c1d5Smjnelson		# Parent is not a real workspace, but just a raw
1905cdf0c1d5Smjnelson		# directory tree - use the file that's there as
1906cdf0c1d5Smjnelson		# the old file.
1907cdf0c1d5Smjnelson
1908cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1909cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1910cdf0c1d5Smjnelson	else
1911cdf0c1d5Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
1912cdf0c1d5Smjnelson			real_parent=$PWS
1913cdf0c1d5Smjnelson		else
1914cdf0c1d5Smjnelson			real_parent=$RWS
1915cdf0c1d5Smjnelson		fi
1916cdf0c1d5Smjnelson
1917cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
1918cdf0c1d5Smjnelson
1919cdf0c1d5Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
1920cdf0c1d5Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
1921cdf0c1d5Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
1922cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1923cdf0c1d5Smjnelson			else
1924cdf0c1d5Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
1925cdf0c1d5Smjnelson				    $olddir/$PDIR/$PF
1926cdf0c1d5Smjnelson			fi
1927cdf0c1d5Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
1928cdf0c1d5Smjnelson			    $olddir/$PDIR/$PF
1929cdf0c1d5Smjnelson		fi
1930cdf0c1d5Smjnelson	fi
1931cdf0c1d5Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
1932cdf0c1d5Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
1933cdf0c1d5Smjnelson	fi
1934cdf0c1d5Smjnelson}
1935cdf0c1d5Smjnelson
1936cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1937cdf0c1d5Smjnelson{
1938cdf0c1d5Smjnelson	typeset olddir="$1"
1939cdf0c1d5Smjnelson	typeset newdir="$2"
1940cdf0c1d5Smjnelson	typeset old_mode=
1941cdf0c1d5Smjnelson	typeset new_mode=
1942cdf0c1d5Smjnelson	typeset file
1943cdf0c1d5Smjnelson
1944cdf0c1d5Smjnelson	#
1945cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1946cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1947cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1948cdf0c1d5Smjnelson	#
1949cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1950cdf0c1d5Smjnelson		file="$PF"
1951cdf0c1d5Smjnelson	else
1952cdf0c1d5Smjnelson		file="$PDIR/$PF"
1953cdf0c1d5Smjnelson	fi
1954b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
1955cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1956b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1957cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1958cdf0c1d5Smjnelson
1959cdf0c1d5Smjnelson	#
1960cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1961cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1962cdf0c1d5Smjnelson	#
1963cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1964cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1965cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1966cdf0c1d5Smjnelson			new_mode=755
1967cdf0c1d5Smjnelson		else
1968cdf0c1d5Smjnelson			new_mode=644
1969cdf0c1d5Smjnelson		fi
1970cdf0c1d5Smjnelson	fi
1971cdf0c1d5Smjnelson
1972cdf0c1d5Smjnelson	#
1973cdf0c1d5Smjnelson	# new version of the file.
1974cdf0c1d5Smjnelson	#
1975cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1976cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1977cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1978cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1979cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1980cdf0c1d5Smjnelson		else
1981cdf0c1d5Smjnelson			# should never happen
1982cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1983cdf0c1d5Smjnelson		fi
1984cdf0c1d5Smjnelson	fi
1985cdf0c1d5Smjnelson
1986cdf0c1d5Smjnelson	#
1987cdf0c1d5Smjnelson	# parent's version of the file
1988cdf0c1d5Smjnelson	#
1989cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1990cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1991cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1992cdf0c1d5Smjnelson	#
1993cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1994cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1995cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1996cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1997cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1998cdf0c1d5Smjnelson
199902d26c39SVladimir Kotal		if (( $? != 0 )); then
2000cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
2001cdf0c1d5Smjnelson		else
2002cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
2003cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
2004cdf0c1d5Smjnelson			else
2005cdf0c1d5Smjnelson				# should never happen
2006cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
2007cdf0c1d5Smjnelson			fi
2008cdf0c1d5Smjnelson		fi
2009cdf0c1d5Smjnelson	fi
2010cdf0c1d5Smjnelson}
2011cdf0c1d5Smjnelson
2012cdf0c1d5Smjnelsonfunction build_old_new_subversion
2013cdf0c1d5Smjnelson{
2014cdf0c1d5Smjnelson	typeset olddir="$1"
2015cdf0c1d5Smjnelson	typeset newdir="$2"
2016cdf0c1d5Smjnelson
2017cdf0c1d5Smjnelson	# Snag new version of file.
2018cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2019cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2020cdf0c1d5Smjnelson
2021cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2022cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2023cdf0c1d5Smjnelson	else
2024cdf0c1d5Smjnelson		# Get the parent's version of the file.
2025cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2026cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2027cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2028cdf0c1d5Smjnelson		fi
2029cdf0c1d5Smjnelson	fi
2030cdf0c1d5Smjnelson}
2031cdf0c1d5Smjnelson
2032cdf0c1d5Smjnelsonfunction build_old_new_unknown
2033cdf0c1d5Smjnelson{
2034cdf0c1d5Smjnelson	typeset olddir="$1"
2035cdf0c1d5Smjnelson	typeset newdir="$2"
2036cdf0c1d5Smjnelson
2037cdf0c1d5Smjnelson	#
2038cdf0c1d5Smjnelson	# Snag new version of file.
2039cdf0c1d5Smjnelson	#
2040cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2041cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2042cdf0c1d5Smjnelson
2043cdf0c1d5Smjnelson	#
2044cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2045cdf0c1d5Smjnelson	#
2046cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2047cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2048cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2049cdf0c1d5Smjnelson	fi
2050cdf0c1d5Smjnelson}
2051cdf0c1d5Smjnelson
2052cdf0c1d5Smjnelsonfunction build_old_new
2053cdf0c1d5Smjnelson{
2054cdf0c1d5Smjnelson	typeset WDIR=$1
2055cdf0c1d5Smjnelson	typeset PWS=$2
2056cdf0c1d5Smjnelson	typeset PDIR=$3
2057cdf0c1d5Smjnelson	typeset PF=$4
2058cdf0c1d5Smjnelson	typeset CWS=$5
2059cdf0c1d5Smjnelson	typeset DIR=$6
2060cdf0c1d5Smjnelson	typeset F=$7
2061cdf0c1d5Smjnelson
2062cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2063cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2064cdf0c1d5Smjnelson
2065cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2066cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2067cdf0c1d5Smjnelson
2068cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2069cdf0c1d5Smjnelson		build_old_new_teamware "$olddir" "$newdir"
2070cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
2071cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
2072cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2073cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2074cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2075cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2076cdf0c1d5Smjnelson	fi
2077cdf0c1d5Smjnelson
2078cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2079cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2080cdf0c1d5Smjnelson		return 1
2081cdf0c1d5Smjnelson	fi
2082cdf0c1d5Smjnelson	return 0
2083cdf0c1d5Smjnelson}
2084cdf0c1d5Smjnelson
2085cdf0c1d5Smjnelson
2086daaffb31Sdp#
2087daaffb31Sdp# Usage message.
2088daaffb31Sdp#
2089daaffb31Sdpfunction usage
2090daaffb31Sdp{
2091daaffb31Sdp	print 'Usage:\twebrev [common-options]
2092daaffb31Sdp	webrev [common-options] ( <file> | - )
2093daaffb31Sdp	webrev [common-options] -w <wx file>
2094daaffb31Sdp
2095daaffb31SdpOptions:
2096ba44d8a2SVladimir Kotal	-D: delete remote webrev
2097daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
2098ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2099ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2100daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2101daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
210202d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
210302d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2104daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2105daaffb31Sdp
2106daaffb31SdpEnvironment:
2107daaffb31Sdp	WDIR: Control the output directory.
2108daaffb31Sdp	WEBREV_BUGURL: Control the URL prefix for bugids.
2109daaffb31Sdp	WEBREV_SACURL: Control the URL prefix for ARC cases.
2110ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2111daaffb31Sdp
2112cdf0c1d5SmjnelsonSCM Specific Options:
2113cdf0c1d5Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
2114cdf0c1d5Smjnelson
2115daaffb31SdpSCM Environment:
2116cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2117cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2118daaffb31Sdp'
2119daaffb31Sdp
2120daaffb31Sdp	exit 2
2121daaffb31Sdp}
2122daaffb31Sdp
2123daaffb31Sdp#
2124daaffb31Sdp#
2125daaffb31Sdp# Main program starts here
2126daaffb31Sdp#
2127daaffb31Sdp#
2128daaffb31Sdp
2129daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2130daaffb31Sdp
2131daaffb31Sdpset +o noclobber
2132daaffb31Sdp
2133cdf0c1d5SmjnelsonPATH=$(dirname $(whence $0)):$PATH
2134cdf0c1d5Smjnelson
213514983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
213614983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2137cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
2138cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
213914983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
214014983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
214114983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
214202d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2143cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2144cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2145cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2146cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
214702d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2148b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
214902d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
215002d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
215102d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2152ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
2153cdf0c1d5Smjnelson
2154ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2155ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2156ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
215714983201Sdp
215814983201Sdpif [[ ! -x $PERL ]]; then
215914983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
216014983201Sdp	exit 1
2161daaffb31Sdpfi
216214983201Sdp
2163cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2164cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2165cdf0c1d5Smjnelson	exit 1
2166cdf0c1d5Smjnelsonfi
2167cdf0c1d5Smjnelson
216814983201Sdp#
216914983201Sdp# These aren't fatal, but we want to note them to the user.
217014983201Sdp# We don't warn on the absence of 'wx' until later when we've
217114983201Sdp# determined that we actually need to try to invoke it.
217214983201Sdp#
217314983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
217414983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
217514983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2176daaffb31Sdp
2177daaffb31Sdp# Declare global total counters.
2178daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2179daaffb31Sdp
2180ba44d8a2SVladimir Kotal# default remote host for upload/delete
2181ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2182b0088928SVladimir Kotal# prefixes for upload targets
2183b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2184b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2185ba44d8a2SVladimir Kotal
2186ba44d8a2SVladimir KotalDflag=
218714983201Sdpflist_mode=
218814983201Sdpflist_file=
2189daaffb31Sdpiflag=
219002d26c39SVladimir Kotallflag=
219102d26c39SVladimir KotalNflag=
219202d26c39SVladimir Kotalnflag=
219302d26c39SVladimir KotalOflag=
2194daaffb31Sdpoflag=
2195daaffb31Sdppflag=
219602d26c39SVladimir Kotaltflag=
219702d26c39SVladimir Kotaluflag=
219802d26c39SVladimir KotalUflag=
2199daaffb31Sdpwflag=
220002d26c39SVladimir Kotalremote_target=
2201ba44d8a2SVladimir Kotal
2202ba44d8a2SVladimir Kotal#
2203ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2204ba44d8a2SVladimir Kotal# 	with usr/src/tools/onbld/hgext/cdm.py
2205ba44d8a2SVladimir Kotal#
2206ba44d8a2SVladimir Kotalwhile getopts "i:o:p:lwONnt:UD" opt
2207daaffb31Sdpdo
2208daaffb31Sdp	case $opt in
2209ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2210ba44d8a2SVladimir Kotal
2211daaffb31Sdp	i)	iflag=1
2212daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2213daaffb31Sdp
2214daaffb31Sdp	#
2215daaffb31Sdp	# If -l has been specified, we need to abort further options
2216daaffb31Sdp	# processing, because subsequent arguments are going to be
2217daaffb31Sdp	# arguments to 'putback -n'.
2218daaffb31Sdp	#
2219daaffb31Sdp	l)	lflag=1
2220daaffb31Sdp		break;;
2221daaffb31Sdp
222202d26c39SVladimir Kotal	N)	Nflag=1;;
222302d26c39SVladimir Kotal
222402d26c39SVladimir Kotal	n)	nflag=1;;
2225daaffb31Sdp
2226daaffb31Sdp	O)	Oflag=1;;
2227daaffb31Sdp
222802d26c39SVladimir Kotal	o)	oflag=1
222902d26c39SVladimir Kotal		WDIR=$OPTARG;;
223002d26c39SVladimir Kotal
223102d26c39SVladimir Kotal	p)	pflag=1
223202d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
223302d26c39SVladimir Kotal
223402d26c39SVladimir Kotal	t)	tflag=1
223502d26c39SVladimir Kotal		remote_target=$OPTARG;;
223602d26c39SVladimir Kotal
223702d26c39SVladimir Kotal	U)	Uflag=1;;
223802d26c39SVladimir Kotal
223902d26c39SVladimir Kotal	w)	wflag=1;;
22403df69ef3SDarren Moffat
2241daaffb31Sdp	?)	usage;;
2242daaffb31Sdp	esac
2243daaffb31Sdpdone
2244daaffb31Sdp
2245daaffb31SdpFLIST=/tmp/$$.flist
2246daaffb31Sdp
2247daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2248daaffb31Sdp	usage
2249daaffb31Sdpfi
2250daaffb31Sdp
225102d26c39SVladimir Kotal# more sanity checking
225202d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2253ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2254ba44d8a2SVladimir Kotal	    "without -U"
225502d26c39SVladimir Kotal	exit 1
225602d26c39SVladimir Kotalfi
225702d26c39SVladimir Kotal
2258ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2259ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
226002d26c39SVladimir Kotal	exit 1
226102d26c39SVladimir Kotalfi
226202d26c39SVladimir Kotal
2263daaffb31Sdp#
2264daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2265daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2266daaffb31Sdp#
2267daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
2268daaffb31Sdp	parent_webrev="$codemgr_parent"
2269daaffb31Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
2270daaffb31Sdpfi
2271daaffb31Sdp
2272daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2273daaffb31Sdp	shift $(($OPTIND - 1))
2274daaffb31Sdp
2275daaffb31Sdp	if [[ $1 == "-" ]]; then
2276daaffb31Sdp		cat > $FLIST
227714983201Sdp		flist_mode="stdin"
227814983201Sdp		flist_done=1
227914983201Sdp		shift
2280daaffb31Sdp	elif [[ -n $1 ]]; then
228114983201Sdp		if [[ ! -r $1 ]]; then
2282daaffb31Sdp			print -u2 "$1: no such file or not readable"
2283daaffb31Sdp			usage
2284daaffb31Sdp		fi
2285daaffb31Sdp		cat $1 > $FLIST
228614983201Sdp		flist_mode="file"
228714983201Sdp		flist_file=$1
228814983201Sdp		flist_done=1
228914983201Sdp		shift
2290daaffb31Sdp	else
229114983201Sdp		flist_mode="auto"
2292daaffb31Sdp	fi
2293daaffb31Sdpfi
2294daaffb31Sdp
2295daaffb31Sdp#
2296daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2297daaffb31Sdp# is in use.
2298daaffb31Sdp#
2299cdf0c1d5Smjnelson$WHICH_SCM | read SCM_MODE junk || exit 1
2300cdf0c1d5Smjnelsoncase "$SCM_MODE" in
2301cdf0c1d5Smjnelsonteamware|mercurial|subversion)
2302cdf0c1d5Smjnelson	;;
2303cdf0c1d5Smjnelsonunknown)
2304cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2305cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2306cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
23077c478bd9Sstevel@tonic-gate		exit 1
23087c478bd9Sstevel@tonic-gate	fi
2309cdf0c1d5Smjnelson	;;
2310cdf0c1d5Smjnelson*)
2311cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2312cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2313cdf0c1d5Smjnelson		exit 1
2314cdf0c1d5Smjnelson	fi
2315cdf0c1d5Smjnelson	;;
2316cdf0c1d5Smjnelsonesac
23177c478bd9Sstevel@tonic-gate
2318daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2319daaffb31Sdp
2320daaffb31Sdpif [[ -n $lflag ]]; then
2321daaffb31Sdp	#
2322daaffb31Sdp	# If the -l flag is given instead of the name of a file list,
2323daaffb31Sdp	# then generate the file list by extracting file names from a
2324daaffb31Sdp	# putback -n.
2325daaffb31Sdp	#
2326daaffb31Sdp	shift $(($OPTIND - 1))
2327cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
2328daaffb31Sdp		flist_from_teamware "$*"
2329cdf0c1d5Smjnelson	else
2330cdf0c1d5Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
2331cdf0c1d5Smjnelson		exit 1
2332cdf0c1d5Smjnelson	fi
2333daaffb31Sdp	flist_done=1
2334daaffb31Sdp	shift $#
2335daaffb31Sdpelif [[ -n $wflag ]]; then
2336daaffb31Sdp	#
2337daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2338daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2339daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2340daaffb31Sdp	# in building the index.html file.
2341daaffb31Sdp	#
2342daaffb31Sdp	shift $(($OPTIND - 1))
2343daaffb31Sdp	wxfile=$1
2344daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2345daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2346daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2347daaffb31Sdp		fi
2348daaffb31Sdp	fi
2349daaffb31Sdp
2350daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2351daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2352daaffb31Sdp
2353cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2354cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2355cdf0c1d5Smjnelson		usage
2356cdf0c1d5Smjnelson	fi
2357cdf0c1d5Smjnelson
2358daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2359daaffb31Sdp	flist_from_wx $wxfile
2360daaffb31Sdp	flist_done=1
2361daaffb31Sdp	if [[ -n "$*" ]]; then
2362daaffb31Sdp		shift
2363daaffb31Sdp	fi
236414983201Sdpelif [[ $flist_mode == "stdin" ]]; then
236514983201Sdp	print -u2 " File list from: standard input"
236614983201Sdpelif [[ $flist_mode == "file" ]]; then
236714983201Sdp	print -u2 " File list from: $flist_file"
2368daaffb31Sdpfi
2369daaffb31Sdp
2370daaffb31Sdpif [[ $# -gt 0 ]]; then
237114983201Sdp	print -u2 "WARNING: unused arguments: $*"
2372daaffb31Sdpfi
2373daaffb31Sdp
2374daaffb31Sdpif [[ $SCM_MODE == "teamware" ]]; then
2375daaffb31Sdp	#
2376daaffb31Sdp	# Parent (internally $codemgr_parent) and workspace ($codemgr_ws) can
2377daaffb31Sdp	# be set in a number of ways, in decreasing precedence:
2378daaffb31Sdp	#
2379daaffb31Sdp	#      1) on the command line (only for the parent)
2380daaffb31Sdp	#      2) in the user environment
2381daaffb31Sdp	#      3) in the flist
2382daaffb31Sdp	#      4) automatically based on the workspace (only for the parent)
2383daaffb31Sdp	#
2384daaffb31Sdp
2385daaffb31Sdp	#
2386daaffb31Sdp	# Here is case (2): the user environment
2387daaffb31Sdp	#
2388daaffb31Sdp	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
2389daaffb31Sdp	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
2390daaffb31Sdp		print -u2 "$codemgr_ws: no such workspace"
23917c478bd9Sstevel@tonic-gate		exit 1
23927c478bd9Sstevel@tonic-gate	fi
23937c478bd9Sstevel@tonic-gate
2394daaffb31Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
2395daaffb31Sdp	    codemgr_parent=$CODEMGR_PARENT
2396daaffb31Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
2397daaffb31Sdp		print -u2 "$codemgr_parent: no such directory"
23987c478bd9Sstevel@tonic-gate		exit 1
23997c478bd9Sstevel@tonic-gate	fi
24007c478bd9Sstevel@tonic-gate
2401daaffb31Sdp	#
2402daaffb31Sdp	# If we're in auto-detect mode and we haven't already gotten the file
2403daaffb31Sdp	# list, then see if we can get it by probing for wx.
2404daaffb31Sdp	#
240514983201Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
240614983201Sdp		if [[ ! -x $WX ]]; then
240714983201Sdp			print -u2 "WARNING: wx not found!"
2408daaffb31Sdp		fi
24097c478bd9Sstevel@tonic-gate
2410daaffb31Sdp		#
2411daaffb31Sdp		# We need to use wx list -w so that we get renamed files, etc.
2412daaffb31Sdp		# but only if a wx active file exists-- otherwise wx will
2413daaffb31Sdp		# hang asking us to initialize our wx information.
2414daaffb31Sdp		#
241514983201Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
2416daaffb31Sdp			print -u2 " File list from: 'wx list -w' ... \c"
2417daaffb31Sdp			$WX list -w > $FLIST
2418daaffb31Sdp			$WX comments > /tmp/$$.wx_comments
2419daaffb31Sdp			wxfile=/tmp/$$.wx_comments
2420daaffb31Sdp			print -u2 "done"
2421daaffb31Sdp			flist_done=1
2422daaffb31Sdp		fi
2423daaffb31Sdp	fi
2424daaffb31Sdp
2425daaffb31Sdp	#
2426daaffb31Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
2427daaffb31Sdp	# from the command line), eval it to extract environment variables from
2428daaffb31Sdp	# it: This is step (3).
2429daaffb31Sdp	#
2430daaffb31Sdp	env_from_flist
2431daaffb31Sdp
2432daaffb31Sdp	#
2433daaffb31Sdp	# Continuing step (3): If we still have no file list, we'll try to get
2434daaffb31Sdp	# it from teamware.
2435daaffb31Sdp	#
2436daaffb31Sdp	if [[ -z $flist_done ]]; then
2437daaffb31Sdp		flist_from_teamware
2438daaffb31Sdp		env_from_flist
2439daaffb31Sdp	fi
2440daaffb31Sdp
2441daaffb31Sdp	#
2442daaffb31Sdp	# (4) If we still don't have a value for codemgr_parent, get it
2443daaffb31Sdp	# from workspace.
2444daaffb31Sdp	#
2445cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`workspace name`
2446daaffb31Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
2447daaffb31Sdp	if [[ ! -d $codemgr_parent ]]; then
2448daaffb31Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
2449daaffb31Sdp		exit 1
2450daaffb31Sdp	fi
2451daaffb31Sdp
2452daaffb31Sdp	#
2453cdf0c1d5Smjnelson	# Observe true directory name of CODEMGR_WS, as used later in
2454cdf0c1d5Smjnelson	# webrev title.
2455cdf0c1d5Smjnelson	#
2456cdf0c1d5Smjnelson	codemgr_ws=$(cd $codemgr_ws;print $PWD)
2457cdf0c1d5Smjnelson
2458cdf0c1d5Smjnelson	#
2459daaffb31Sdp	# Reset CODEMGR_WS to make sure teamware commands are happy.
2460daaffb31Sdp	#
2461daaffb31Sdp	CODEMGR_WS=$codemgr_ws
2462daaffb31Sdp	CWS=$codemgr_ws
2463daaffb31Sdp	PWS=$codemgr_parent
2464cdf0c1d5Smjnelson
2465cdf0c1d5Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
2466cdf0c1d5Smjnelson
2467cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
2468cdf0c1d5Smjnelson	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
2469cdf0c1d5Smjnelson	    codemgr_ws=`hg root -R $CODEMGR_WS 2>/dev/null`
2470cdf0c1d5Smjnelson
2471cdf0c1d5Smjnelson	[[ -z $codemgr_ws ]] && codemgr_ws=`hg root 2>/dev/null`
2472cdf0c1d5Smjnelson
2473cdf0c1d5Smjnelson	#
2474cdf0c1d5Smjnelson	# Parent can either be specified with -p
2475cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2476cdf0c1d5Smjnelson	# or taken from hg's default path.
2477cdf0c1d5Smjnelson	#
2478cdf0c1d5Smjnelson
2479cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2480cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2481cdf0c1d5Smjnelson	fi
2482cdf0c1d5Smjnelson
2483cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2484cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2485cdf0c1d5Smjnelson	fi
2486cdf0c1d5Smjnelson
2487cdf0c1d5Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
2488cdf0c1d5Smjnelson	CWS=$codemgr_ws
2489cdf0c1d5Smjnelson	PWS=$codemgr_parent
2490cdf0c1d5Smjnelson
2491cdf0c1d5Smjnelson	#
2492cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2493cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2494cdf0c1d5Smjnelson	#
2495cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2496cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2497cdf0c1d5Smjnelson	else
2498cdf0c1d5Smjnelson		real_parent=$PWS
2499cdf0c1d5Smjnelson	fi
2500cdf0c1d5Smjnelson
2501cdf0c1d5Smjnelson	#
2502cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2503cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2504cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2505cdf0c1d5Smjnelson	# files mentioned in the flist.
2506cdf0c1d5Smjnelson	#
2507cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2508cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2509cdf0c1d5Smjnelson		flist_done=1
2510cdf0c1d5Smjnelson	fi
2511cdf0c1d5Smjnelson
2512cdf0c1d5Smjnelson	#
2513cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2514cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2515cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2516cdf0c1d5Smjnelson	# in the user-specified flist.
2517cdf0c1d5Smjnelson	#
2518cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2519cdf0c1d5Smjnelson		env_from_flist
2520cdf0c1d5Smjnelson	fi
2521cdf0c1d5Smjnelson
2522cdf0c1d5Smjnelson	#
2523cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2524cdf0c1d5Smjnelson	#
2525cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2526cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2527cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2528cdf0c1d5Smjnelson		print " Done."
2529cdf0c1d5Smjnelson	fi
2530cdf0c1d5Smjnelson
2531cdf0c1d5Smjnelson	#
2532cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2533cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2534cdf0c1d5Smjnelson	# if we don't have one.
2535cdf0c1d5Smjnelson	#
2536cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2537b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2538cdf0c1d5Smjnelson	fi
2539cdf0c1d5Smjnelson
2540cdf0c1d5Smjnelson	#
2541cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2542cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2543cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2544cdf0c1d5Smjnelson	#
2545cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2546cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2547b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2548cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2549cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2550cdf0c1d5Smjnelson		exit 1
2551cdf0c1d5Smjnelson	fi
2552cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2553cdf0c1d5Smjnelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
2554cdf0c1d5Smjnelson		CWS=$CODEMGR_WS
2555cdf0c1d5Smjnelson	else
2556cdf0c1d5Smjnelson		svn info | while read line; do
2557cdf0c1d5Smjnelson			if [[ $line == "URL: "* ]]; then
2558cdf0c1d5Smjnelson				url=${line#URL: }
2559cdf0c1d5Smjnelson			elif [[ $line == "Repository Root: "* ]]; then
2560cdf0c1d5Smjnelson				repo=${line#Repository Root: }
2561cdf0c1d5Smjnelson			fi
2562cdf0c1d5Smjnelson		done
2563cdf0c1d5Smjnelson
2564cdf0c1d5Smjnelson		rel=${url#$repo}
2565cdf0c1d5Smjnelson		CWS=${PWD%$rel}
2566cdf0c1d5Smjnelson	fi
2567cdf0c1d5Smjnelson
2568cdf0c1d5Smjnelson	#
2569cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2570cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2571cdf0c1d5Smjnelson	#
2572cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2573cdf0c1d5Smjnelson
2574cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2575cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2576cdf0c1d5Smjnelson	fi
2577cdf0c1d5Smjnelsonelse
2578cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2579cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2580cdf0c1d5Smjnelson    else
2581cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2582cdf0c1d5Smjnelson    fi
2583cdf0c1d5Smjnelson
2584cdf0c1d5Smjnelson    env_from_flist
2585cdf0c1d5Smjnelson
2586cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2587cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2588cdf0c1d5Smjnelson	exit 1
2589cdf0c1d5Smjnelson    fi
2590cdf0c1d5Smjnelson
2591cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2592cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2593cdf0c1d5Smjnelson	exit 1
2594cdf0c1d5Smjnelson    fi
2595cdf0c1d5Smjnelson
2596cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2597cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2598daaffb31Sdpfi
2599daaffb31Sdp
2600daaffb31Sdp#
2601daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2602daaffb31Sdp# webrev-info file in the workspace directory.
2603daaffb31Sdp#
2604daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2605daaffb31Sdp	iflag=1
2606daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2607daaffb31Sdpfi
2608daaffb31Sdp
2609daaffb31Sdpif [[ -n $iflag ]]; then
2610daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2611daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2612daaffb31Sdp		    "not readable."
2613daaffb31Sdp		exit 1
2614daaffb31Sdp	else
2615daaffb31Sdp		#
2616daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2617daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2618daaffb31Sdp		#
2619daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2620daaffb31Sdp	fi
2621daaffb31Sdpfi
2622daaffb31Sdp
2623daaffb31Sdp#
2624daaffb31Sdp# Output directory.
2625daaffb31Sdp#
2626daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2627daaffb31Sdp
2628daaffb31Sdp#
262902d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
263002d26c39SVladimir Kotal# in the future this could potentially be an option.
2631daaffb31Sdp#
263202d26c39SVladimir Kotalif [[ -n $oflag ]]; then
263302d26c39SVladimir Kotal	WNAME=${WDIR##*/}
263402d26c39SVladimir Kotalelse
2635daaffb31Sdp	WNAME=${CWS##*/}
263602d26c39SVladimir Kotalfi
263702d26c39SVladimir Kotal
2638ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2639ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2640b0088928SVladimir Kotal	#
2641ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2642ba44d8a2SVladimir Kotal	# the default values.
2643b0088928SVladimir Kotal	#
2644ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2645ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2646ba44d8a2SVladimir Kotal	else
2647b0088928SVladimir Kotal		#
2648b0088928SVladimir Kotal		# Check upload target prefix first.
2649b0088928SVladimir Kotal		#
2650b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
2651b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
2652b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
2653b0088928SVladimir Kotal			    "($remote_target)"
2654b0088928SVladimir Kotal			exit 1
2655b0088928SVladimir Kotal		fi
2656b0088928SVladimir Kotal		#
2657ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2658ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2659ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2660ba44d8a2SVladimir Kotal		# local webrev directory name.
2661b0088928SVladimir Kotal		#
2662b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
2663b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
2664ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2665b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
2666ba44d8a2SVladimir Kotal			fi
2667b0088928SVladimir Kotal		else
2668b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
2669b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
2670b0088928SVladimir Kotal					"($remote_target)"
2671b0088928SVladimir Kotal				exit 1
2672b0088928SVladimir Kotal			else
2673b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
2674ba44d8a2SVladimir Kotal			fi
2675ba44d8a2SVladimir Kotal		fi
2676ba44d8a2SVladimir Kotal	fi
2677ba44d8a2SVladimir Kotal
2678b0088928SVladimir Kotal	#
2679b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
2680b0088928SVladimir Kotal	# specification separately.
2681b0088928SVladimir Kotal	#
2682b0088928SVladimir Kotal	remote_target=${remote_target%/}
2683b0088928SVladimir Kotalfi
2684b0088928SVladimir Kotal
2685b0088928SVladimir Kotal#
2686ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2687b0088928SVladimir Kotal#
2688ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2689b0088928SVladimir Kotal	delete_webrev 1 1
2690ba44d8a2SVladimir Kotal	exit $?
2691ba44d8a2SVladimir Kotalfi
2692ba44d8a2SVladimir Kotal
2693b0088928SVladimir Kotal#
2694ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2695b0088928SVladimir Kotal#
2696ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2697ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2698b0088928SVladimir Kotal		delete_webrev 1 1
2699ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2700ba44d8a2SVladimir Kotal	fi
2701ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
270202d26c39SVladimir Kotal		upload_webrev
270302d26c39SVladimir Kotal		exit $?
270402d26c39SVladimir Kotal	fi
2705ba44d8a2SVladimir Kotalfi
2706daaffb31Sdp
2707e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
27087c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
27097c478bd9Sstevel@tonic-gatefi
2710daaffb31Sdp
2711daaffb31Sdpif [[ ! -d $WDIR ]]; then
2712daaffb31Sdp	mkdir -p $WDIR
2713ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
27147c478bd9Sstevel@tonic-gatefi
27157c478bd9Sstevel@tonic-gate
2716daaffb31Sdp#
2717daaffb31Sdp# Summarize what we're going to do.
2718daaffb31Sdp#
2719cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
2720cdf0c1d5Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
2721cdf0c1d5Smjnelsonelse
2722daaffb31Sdp	print "      Workspace: $CWS"
2723cdf0c1d5Smjnelsonfi
2724daaffb31Sdpif [[ -n $parent_webrev ]]; then
2725daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2726daaffb31Sdpelse
2727cdf0c1d5Smjnelson	if [[ -n $HG_PARENT ]]; then
2728cdf0c1d5Smjnelson		hg_parent_short=`echo $HG_PARENT \
2729b0088928SVladimir Kotal			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
2730cdf0c1d5Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
2731cdf0c1d5Smjnelson	else
2732daaffb31Sdp		print "Compare against: $PWS"
2733daaffb31Sdp	fi
2734cdf0c1d5Smjnelsonfi
2735daaffb31Sdp
2736daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2737daaffb31Sdpprint "      Output to: $WDIR"
2738daaffb31Sdp
2739daaffb31Sdp#
27407c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2741daaffb31Sdp#
2742daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
27437c478bd9Sstevel@tonic-gate
2744daaffb31Sdp#
2745daaffb31Sdp#    Bug IDs will be replaced by a URL.  Order of precedence
2746daaffb31Sdp#    is: default location, $WEBREV_BUGURL, the -O flag.
2747daaffb31Sdp#
2748daaffb31SdpBUGURL='http://monaco.sfbay.sun.com/detail.jsp?cr='
2749daaffb31Sdp[[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
2750daaffb31Sdp[[ -n "$Oflag" ]] && \
2751daaffb31Sdp    BUGURL='http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id='
27527c478bd9Sstevel@tonic-gate
2753daaffb31Sdp#
2754daaffb31Sdp#    Likewise, ARC cases will be replaced by a URL.  Order of precedence
2755daaffb31Sdp#    is: default, $WEBREV_SACURL, the -O flag.
2756daaffb31Sdp#
2757daaffb31Sdp#    Note that -O also triggers different substitution behavior for
2758daaffb31Sdp#    SACURL.  See sac2url().
2759daaffb31Sdp#
2760daaffb31SdpSACURL='http://sac.eng.sun.com'
2761daaffb31Sdp[[ -n $WEBREV_SACURL ]] && SACURL="$WEBREV_SACURL"
2762e0e0293aSjmcp[[ -n "$Oflag" ]] && \
2763daaffb31Sdp    SACURL='http://www.opensolaris.org/os/community/arc/caselog'
27647c478bd9Sstevel@tonic-gate
2765daaffb31Sdprm -f $WDIR/$WNAME.patch
2766daaffb31Sdprm -f $WDIR/$WNAME.ps
2767daaffb31Sdprm -f $WDIR/$WNAME.pdf
27687c478bd9Sstevel@tonic-gate
2769daaffb31Sdptouch $WDIR/$WNAME.patch
27707c478bd9Sstevel@tonic-gate
2771daaffb31Sdpprint "   Output Files:"
2772daaffb31Sdp
2773daaffb31Sdp#
2774daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2775daaffb31Sdp#
2776b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2777daaffb31SdpFLIST=/tmp/$$.flist.clean
2778daaffb31Sdp
2779daaffb31Sdp#
2780cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2781cdf0c1d5Smjnelson#
2782cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2783cdf0c1d5Smjnelson	#
2784cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2785cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2786cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2787cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2788cdf0c1d5Smjnelson	#    keep only the old name.
2789cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2790cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2791cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2792cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2793cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2794cdf0c1d5Smjnelson	#
2795cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2796b0088928SVladimir Kotal	$SED '
2797cdf0c1d5Smjnelson		s#^[^ ]* ##
2798cdf0c1d5Smjnelson		s#/#\\\/#g
2799cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2800cdf0c1d5Smjnelson	' < $FLIST > $SEDFILE
2801cdf0c1d5Smjnelson
2802cdf0c1d5Smjnelson	#
2803cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2804cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2805cdf0c1d5Smjnelson	#
2806cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2807cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2808b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2809cdf0c1d5Smjnelsonfi
2810cdf0c1d5Smjnelson
2811cdf0c1d5Smjnelson#
2812daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
2813daaffb31Sdp#
2814daaffb31Sdpcat $FLIST | while read LINE
28157c478bd9Sstevel@tonic-gatedo
28167c478bd9Sstevel@tonic-gate	set - $LINE
28177c478bd9Sstevel@tonic-gate	P=$1
28187c478bd9Sstevel@tonic-gate
2819daaffb31Sdp	#
2820daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
2821daaffb31Sdp	# file that has been modified or created in the child.  A file
2822daaffb31Sdp	# that is renamed in the child workspace has two names on the
2823daaffb31Sdp	# line: new name followed by the old name.
2824daaffb31Sdp	#
2825daaffb31Sdp	oldname=""
2826daaffb31Sdp	oldpath=""
2827daaffb31Sdp	rename=
2828daaffb31Sdp	if [[ $# -eq 2 ]]; then
28297c478bd9Sstevel@tonic-gate		PP=$2			# old filename
2830daaffb31Sdp		oldname=" (was $PP)"
2831daaffb31Sdp		oldpath="$PP"
2832daaffb31Sdp		rename=1
28337c478bd9Sstevel@tonic-gate        	PDIR=${PP%/*}
2834daaffb31Sdp        	if [[ $PDIR == $PP ]]; then
28357c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
28367c478bd9Sstevel@tonic-gate		fi
28377c478bd9Sstevel@tonic-gate
28387c478bd9Sstevel@tonic-gate		PF=${PP##*/}
28397c478bd9Sstevel@tonic-gate
28407c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2841daaffb31Sdp	        if [[ $DIR == $P ]]; then
28427c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
28437c478bd9Sstevel@tonic-gate		fi
28447c478bd9Sstevel@tonic-gate
28457c478bd9Sstevel@tonic-gate		F=${P##*/}
2846daaffb31Sdp
28477c478bd9Sstevel@tonic-gate        else
28487c478bd9Sstevel@tonic-gate	        DIR=${P%/*}
2849daaffb31Sdp	        if [[ "$DIR" == "$P" ]]; then
28507c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
28517c478bd9Sstevel@tonic-gate		fi
28527c478bd9Sstevel@tonic-gate
28537c478bd9Sstevel@tonic-gate		F=${P##*/}
28547c478bd9Sstevel@tonic-gate
28557c478bd9Sstevel@tonic-gate		PP=$P
28567c478bd9Sstevel@tonic-gate		PDIR=$DIR
28577c478bd9Sstevel@tonic-gate		PF=$F
28587c478bd9Sstevel@tonic-gate	fi
28597c478bd9Sstevel@tonic-gate
2860daaffb31Sdp	COMM=`getcomments html $P $PP`
28617c478bd9Sstevel@tonic-gate
2862daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
28637c478bd9Sstevel@tonic-gate
28647c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
28657c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
28667c478bd9Sstevel@tonic-gate
2867daaffb31Sdp	#
2868daaffb31Sdp	# If we're in OpenSolaris mode, we enforce a minor policy:
2869daaffb31Sdp	# help to make sure the reviewer doesn't accidentally publish
2870e0e0293aSjmcp	# source which is in usr/closed/* or deleted_files/usr/closed/*
2871daaffb31Sdp	#
2872e0e0293aSjmcp	if [[ -n "$Oflag" ]]; then
2873daaffb31Sdp		pclosed=${P##usr/closed/}
2874e0e0293aSjmcp		pdeleted=${P##deleted_files/usr/closed/}
2875e0e0293aSjmcp		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
2876daaffb31Sdp			print "*** Omitting closed source for OpenSolaris" \
2877daaffb31Sdp			    "mode review"
2878daaffb31Sdp			continue
2879daaffb31Sdp		fi
2880daaffb31Sdp	fi
2881daaffb31Sdp
2882daaffb31Sdp	#
2883cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
2884daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
2885daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
2886daaffb31Sdp	#
2887daaffb31Sdp
2888cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
28897c478bd9Sstevel@tonic-gate	    continue
28907c478bd9Sstevel@tonic-gate
2891cdf0c1d5Smjnelson	#
2892cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
2893cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
2894cdf0c1d5Smjnelson	# consistent environment.
2895cdf0c1d5Smjnelson	#
2896cdf0c1d5Smjnelson	OWD=$PWD
2897daaffb31Sdp	cd $WDIR/raw_files
2898daaffb31Sdp	ofile=old/$PDIR/$PF
2899daaffb31Sdp	nfile=new/$DIR/$F
29007c478bd9Sstevel@tonic-gate
2901daaffb31Sdp	mv_but_nodiff=
2902daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
2903daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
2904daaffb31Sdp		mv_but_nodiff=1
2905daaffb31Sdp	fi
2906daaffb31Sdp
2907daaffb31Sdp	#
2908daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
2909daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
2910daaffb31Sdp	#
2911daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
2912daaffb31Sdp	#	  diff and an 'add' diff
2913daaffb31Sdp	#	- new files and deleted files must be handled specially
2914daaffb31Sdp	#	- Solaris patch(1m) can't cope with file creation
2915daaffb31Sdp	#	  (and hence renames) as of this writing.
2916daaffb31Sdp	#       - To make matters worse, gnu patch doesn't interpret the
2917daaffb31Sdp	#	  output of Solaris diff properly when it comes to
2918daaffb31Sdp	#	  adds and deletes.  We need to do some "cleansing"
2919daaffb31Sdp	#         transformations:
2920daaffb31Sdp	# 	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
2921daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
2922daaffb31Sdp	#
2923b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
2924b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
2925daaffb31Sdp
2926daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
2927daaffb31Sdp	if [[ -z $rename ]]; then
2928e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
2929daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2930daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2931e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
2932daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2933daaffb31Sdp			    > $WDIR/$DIR/$F.patch
2934daaffb31Sdp		else
2935daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
2936daaffb31Sdp		fi
2937daaffb31Sdp	else
2938daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
2939daaffb31Sdp		    > $WDIR/$DIR/$F.patch
2940daaffb31Sdp
2941daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
2942daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
2943daaffb31Sdp
2944daaffb31Sdp	fi
2945daaffb31Sdp
2946daaffb31Sdp	#
2947daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
2948daaffb31Sdp	# whole wad.
2949daaffb31Sdp	#
2950daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
2951daaffb31Sdp
2952daaffb31Sdp	print " patch\c"
2953daaffb31Sdp
2954daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
2955daaffb31Sdp
2956daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
2957daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
2958daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
29597c478bd9Sstevel@tonic-gate		print " cdiffs\c"
29607c478bd9Sstevel@tonic-gate
2961daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
2962daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
2963daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
2964daaffb31Sdp
29657c478bd9Sstevel@tonic-gate		print " udiffs\c"
29667c478bd9Sstevel@tonic-gate
29677c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
2968daaffb31Sdp			$WDIFF -c "$COMM" \
2969daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
2970daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
2971daaffb31Sdp			if [[ $? -eq 0 ]]; then
29727c478bd9Sstevel@tonic-gate				print " wdiffs\c"
2973daaffb31Sdp			else
2974daaffb31Sdp				print " wdiffs[fail]\c"
2975daaffb31Sdp			fi
29767c478bd9Sstevel@tonic-gate		fi
29777c478bd9Sstevel@tonic-gate
2978daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
2979daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
29807c478bd9Sstevel@tonic-gate		print " sdiffs\c"
29817c478bd9Sstevel@tonic-gate
29827c478bd9Sstevel@tonic-gate		print " frames\c"
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
29857c478bd9Sstevel@tonic-gate
2986daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2987daaffb31Sdp
2988daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
2989daaffb31Sdp		# renamed file: may also have differences
2990daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
2991daaffb31Sdp	elif [[ -f $nfile ]]; then
29927c478bd9Sstevel@tonic-gate		# new file: count added lines
2993daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
2994daaffb31Sdp	elif [[ -f $ofile ]]; then
29957c478bd9Sstevel@tonic-gate		# old file: count deleted lines
2996daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
29977c478bd9Sstevel@tonic-gate	fi
29987c478bd9Sstevel@tonic-gate
2999daaffb31Sdp	#
3000daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3001daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3002daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3003daaffb31Sdp	#
3004daaffb31Sdp	if [[ -f $nfile ]]; then
3005daaffb31Sdp		ocr=$ofile
3006daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3007daaffb31Sdp
3008daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3009daaffb31Sdp			textcomm=`getcomments text $P $PP`
301014983201Sdp			if [[ -x $CODEREVIEW ]]; then
301114983201Sdp				$CODEREVIEW -y "$textcomm" \
301214983201Sdp				    -e $ocr $nfile \
301314983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
301414983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3015daaffb31Sdp				if [[ $? -eq 0 ]]; then
3016daaffb31Sdp					print " ps\c"
3017daaffb31Sdp				else
3018daaffb31Sdp					print " ps[fail]\c"
3019daaffb31Sdp				fi
3020daaffb31Sdp			fi
3021daaffb31Sdp		fi
302214983201Sdp	fi
3023daaffb31Sdp
3024cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3025cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
30267c478bd9Sstevel@tonic-gate		print " old\c"
30277c478bd9Sstevel@tonic-gate	fi
30287c478bd9Sstevel@tonic-gate
3029daaffb31Sdp	if [[ -f $nfile ]]; then
3030daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
30317c478bd9Sstevel@tonic-gate		print " new\c"
30327c478bd9Sstevel@tonic-gate	fi
30337c478bd9Sstevel@tonic-gate
3034cdf0c1d5Smjnelson	cd $OWD
3035cdf0c1d5Smjnelson
3036daaffb31Sdp	print
30377c478bd9Sstevel@tonic-gatedone
30387c478bd9Sstevel@tonic-gate
3039daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
30407c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3041daaffb31Sdp
304214983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
304314983201Sdp	print " Generating PDF: Skipped: no output available"
304414983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
304514983201Sdp	print " Generating PDF: \c"
304614983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3047daaffb31Sdp	print "Done."
304814983201Sdpelse
304914983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
305014983201Sdpfi
30517c478bd9Sstevel@tonic-gate
3052e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3053e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3054e0e0293aSjmcp
3055e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3056ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3057e0e0293aSjmcpfi
3058e0e0293aSjmcp
30597c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
30607c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
30617c478bd9Sstevel@tonic-gate
30627c478bd9Sstevel@tonic-gatecd $CWS
30637c478bd9Sstevel@tonic-gate
30647c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3065daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
30667c478bd9Sstevel@tonic-gate
3067daaffb31Sdpprint "     index.html: \c"
30687c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
30697c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
30707c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
30717c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
30727c478bd9Sstevel@tonic-gate
3073daaffb31Sdpprint "$HTML<head>$STDHEAD"
3074daaffb31Sdpprint "<title>$WNAME</title>"
3075daaffb31Sdpprint "</head>"
3076daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3077daaffb31Sdpprint "<div class=\"summary\">"
3078daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
30797c478bd9Sstevel@tonic-gate
3080daaffb31Sdpprint "<table>"
30817c478bd9Sstevel@tonic-gate
3082daaffb31Sdp#
3083cdf0c1d5Smjnelson# Get the preparer's name:
3084daaffb31Sdp#
3085cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3086cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3087cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3088cdf0c1d5Smjnelson#
3089cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3090cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3091cdf0c1d5Smjnelson#
3092cdf0c1d5Smjnelsonpreparer=
3093cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3094cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3095cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3096cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3097cdf0c1d5Smjnelson	fi
3098cdf0c1d5Smjnelsonfi
3099cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3100cdf0c1d5Smjnelson	preparer=$(
3101cdf0c1d5Smjnelson	    $PERL -e '
3102cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3103cdf0c1d5Smjnelson	        if ($login) {
3104cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3105cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3106cdf0c1d5Smjnelson	        } else {
3107cdf0c1d5Smjnelson	            printf "(unknown)\n";
3108cdf0c1d5Smjnelson	        }
3109cdf0c1d5Smjnelson	')
3110daaffb31Sdpfi
3111daaffb31Sdp
3112cdf0c1d5Smjnelsonprint "<tr><th>Prepared by:</th><td>$preparer on `date`</td></tr>"
3113cdf0c1d5Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
3114cdf0c1d5Smjnelsonif [[ -n $CWS_REV ]]; then
3115cdf0c1d5Smjnelson	print "(at $CWS_REV)"
3116cdf0c1d5Smjnelsonfi
3117cdf0c1d5Smjnelsonprint "</td></tr>"
3118daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3119daaffb31Sdpif [[ -n $parent_webrev ]]; then
3120daaffb31Sdp	print "webrev at $parent_webrev"
3121daaffb31Sdpelse
3122daaffb31Sdp	print "$PWS"
3123cdf0c1d5Smjnelson	if [[ -n $hg_parent_short ]]; then
3124cdf0c1d5Smjnelson		print "(at $hg_parent_short)"
3125cdf0c1d5Smjnelson	fi
3126daaffb31Sdpfi
3127daaffb31Sdpprint "</td></tr>"
3128daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3129daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3130daaffb31Sdpprint "</td></tr>"
3131daaffb31Sdp
3132daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3133371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3134daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3135371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3136daaffb31Sdpfi
3137daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3138371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3139daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3140371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3141daaffb31Sdpfi
3142daaffb31Sdp
3143daaffb31Sdpif [[ -n "$iflag" ]]; then
3144daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3145daaffb31Sdp	cat /tmp/$$.include
3146daaffb31Sdp	print "</div></td></tr>"
3147daaffb31Sdpfi
3148daaffb31Sdpprint "</table>"
3149daaffb31Sdpprint "</div>"
3150daaffb31Sdp
3151daaffb31Sdp#
3152daaffb31Sdp# Second pass through the files: generate the rest of the index file
3153daaffb31Sdp#
3154daaffb31Sdpcat $FLIST | while read LINE
31557c478bd9Sstevel@tonic-gatedo
31567c478bd9Sstevel@tonic-gate	set - $LINE
31577c478bd9Sstevel@tonic-gate	P=$1
31587c478bd9Sstevel@tonic-gate
3159daaffb31Sdp	if [[ $# == 2 ]]; then
31607c478bd9Sstevel@tonic-gate		PP=$2
3161cdf0c1d5Smjnelson		oldname="$PP"
31627c478bd9Sstevel@tonic-gate	else
31637c478bd9Sstevel@tonic-gate		PP=$P
3164daaffb31Sdp		oldname=""
3165daaffb31Sdp	fi
3166daaffb31Sdp
3167cdf0c1d5Smjnelson	mv_but_nodiff=
3168cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3169cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3170cdf0c1d5Smjnelson		mv_but_nodiff=1
3171cdf0c1d5Smjnelson	fi
3172cdf0c1d5Smjnelson
3173daaffb31Sdp	DIR=${P%/*}
3174daaffb31Sdp	if [[ $DIR == $P ]]; then
3175daaffb31Sdp		DIR="."   # File at root of workspace
31767c478bd9Sstevel@tonic-gate	fi
31777c478bd9Sstevel@tonic-gate
31787c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
31797c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
31807c478bd9Sstevel@tonic-gate	# appear twice in the file list
31817c478bd9Sstevel@tonic-gate
31827c478bd9Sstevel@tonic-gate	F=$WDIR/$P
31837c478bd9Sstevel@tonic-gate
3184daaffb31Sdp	print "<p>"
31857c478bd9Sstevel@tonic-gate
31867c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
31877c478bd9Sstevel@tonic-gate
3188daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3189371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3190371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
3191371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3192371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
31937c478bd9Sstevel@tonic-gate
3194daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3195371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3196371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
31977c478bd9Sstevel@tonic-gate		fi
31987c478bd9Sstevel@tonic-gate
3199371d72daSLubomir Sedlacik		sdiff_url="$(print $P.sdiff.html | url_encode)"
3200371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
32017c478bd9Sstevel@tonic-gate
3202371d72daSLubomir Sedlacik		frames_url="$(print $P.frames.html | url_encode)"
3203371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
32047c478bd9Sstevel@tonic-gate	else
3205daaffb31Sdp		print " ------ ------ ------"
32067c478bd9Sstevel@tonic-gate
3207daaffb31Sdp		if [[ -x $WDIFF ]]; then
32087c478bd9Sstevel@tonic-gate			print " ------"
32097c478bd9Sstevel@tonic-gate		fi
3210daaffb31Sdp
3211daaffb31Sdp		print " ------"
32127c478bd9Sstevel@tonic-gate	fi
32137c478bd9Sstevel@tonic-gate
32147c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
32157c478bd9Sstevel@tonic-gate
3216daaffb31Sdp	if [[ -f $F-.html ]]; then
3217371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3218371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
32197c478bd9Sstevel@tonic-gate	else
3220daaffb31Sdp		print " ---"
32217c478bd9Sstevel@tonic-gate	fi
32227c478bd9Sstevel@tonic-gate
32237c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
32247c478bd9Sstevel@tonic-gate
3225daaffb31Sdp	if [[ -f $F.html ]]; then
3226371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3227371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
32287c478bd9Sstevel@tonic-gate	else
3229daaffb31Sdp		print " ---"
32307c478bd9Sstevel@tonic-gate	fi
32317c478bd9Sstevel@tonic-gate
3232daaffb31Sdp	if [[ -f $F.patch ]]; then
3233371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3234371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3235daaffb31Sdp	else
3236daaffb31Sdp		print " -----"
3237daaffb31Sdp	fi
3238daaffb31Sdp
3239daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3240371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3241371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3242daaffb31Sdp	else
3243daaffb31Sdp		print " ---"
3244daaffb31Sdp	fi
3245daaffb31Sdp
3246cdf0c1d5Smjnelson	print "<b>$P</b>"
3247cdf0c1d5Smjnelson
3248cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3249cdf0c1d5Smjnelson	if [[ -n "$oldname" ]]; then
3250cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3251cdf0c1d5Smjnelson			print "<i>(renamed only, was $oldname)</i>"
3252cdf0c1d5Smjnelson		else
3253cdf0c1d5Smjnelson			print "<i>(modified and renamed, was $oldname)</i>"
3254cdf0c1d5Smjnelson		fi
3255cdf0c1d5Smjnelson	fi
3256cdf0c1d5Smjnelson
3257cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3258cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3259cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3260cdf0c1d5Smjnelson	fi
3261daaffb31Sdp
3262daaffb31Sdp	#
3263e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3264daaffb31Sdp	#
3265daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3266e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3267e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3268daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3269daaffb31Sdp			    "this review</i>"
3270daaffb31Sdp		fi
3271daaffb31Sdp	fi
3272daaffb31Sdp
3273daaffb31Sdp	print "</p>"
32747c478bd9Sstevel@tonic-gate	# Insert delta comments
32757c478bd9Sstevel@tonic-gate
3276daaffb31Sdp	print "<blockquote><pre>"
3277daaffb31Sdp	getcomments html $P $PP
3278daaffb31Sdp	print "</pre>"
32797c478bd9Sstevel@tonic-gate
32807c478bd9Sstevel@tonic-gate	# Add additional comments comment
32817c478bd9Sstevel@tonic-gate
3282daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
32837c478bd9Sstevel@tonic-gate
32847c478bd9Sstevel@tonic-gate	# Add count of changes.
32857c478bd9Sstevel@tonic-gate
3286daaffb31Sdp	if [[ -f $F.count ]]; then
32877c478bd9Sstevel@tonic-gate	    cat $F.count
32887c478bd9Sstevel@tonic-gate	    rm $F.count
32897c478bd9Sstevel@tonic-gate	fi
3290cdf0c1d5Smjnelson
3291cdf0c1d5Smjnelson	if [[ $SCM_MODE == "teamware" ||
3292cdf0c1d5Smjnelson	    $SCM_MODE == "mercurial" ||
3293cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3294cdf0c1d5Smjnelson
3295cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3296cdf0c1d5Smjnelson		# 1) New executable files
3297cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3298cdf0c1d5Smjnelson		# 3) Existing executable files
3299cdf0c1d5Smjnelson
3300cdf0c1d5Smjnelson		old_mode=
3301cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3302cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3303cdf0c1d5Smjnelson		fi
3304cdf0c1d5Smjnelson
3305cdf0c1d5Smjnelson		new_mode=
3306cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3307cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3308cdf0c1d5Smjnelson		fi
3309cdf0c1d5Smjnelson
3310cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3311cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3312cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3313cdf0c1d5Smjnelson			print "</span>"
3314cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3315cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3316cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3317cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3318cdf0c1d5Smjnelson			print "</span>"
3319cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3320cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3321cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3322cdf0c1d5Smjnelson			print "</span>"
3323cdf0c1d5Smjnelson		fi
3324cdf0c1d5Smjnelson	fi
3325cdf0c1d5Smjnelson
3326daaffb31Sdp	print "</blockquote>"
33277c478bd9Sstevel@tonic-gatedone
33287c478bd9Sstevel@tonic-gate
3329daaffb31Sdpprint
3330daaffb31Sdpprint
3331cac38512Smjnelsonprint "<hr></hr>"
3332daaffb31Sdpprint "<p style=\"font-size: small\">"
33339a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
3334daaffb31Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
3335daaffb31Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
3336e9e2cfb2Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3337daaffb31Sdpprint "</body>"
3338daaffb31Sdpprint "</html>"
33397c478bd9Sstevel@tonic-gate
33407c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
33417c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
33427c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
33437c478bd9Sstevel@tonic-gate
3344daaffb31Sdpprint "Done."
334502d26c39SVladimir Kotal
3346b0088928SVladimir Kotal#
3347ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3348b0088928SVladimir Kotal#
3349ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3350b0088928SVladimir Kotal	delete_webrev 1 1
3351ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3352ba44d8a2SVladimir Kotalfi
3353ba44d8a2SVladimir Kotal
335402d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
335502d26c39SVladimir Kotal	upload_webrev
335602d26c39SVladimir Kotal	exit $?
335702d26c39SVladimir Kotalfi
3358