xref: /onnv-gate/usr/src/tools/scripts/webrev.sh (revision 12776:0a254b4b5ca4)
19196SMark.J.Nelson@Sun.COM#!/usr/bin/ksh93 -p
20Sstevel@tonic-gate#
30Sstevel@tonic-gate# CDDL HEADER START
40Sstevel@tonic-gate#
50Sstevel@tonic-gate# The contents of this file are subject to the terms of the
63252Sdp# Common Development and Distribution License (the "License").
73252Sdp# You may not use this file except in compliance with the License.
80Sstevel@tonic-gate#
90Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate# See the License for the specific language governing permissions
120Sstevel@tonic-gate# and limitations under the License.
130Sstevel@tonic-gate#
140Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate#
200Sstevel@tonic-gate# CDDL HEADER END
210Sstevel@tonic-gate#
227298SMark.J.Nelson@Sun.COM
230Sstevel@tonic-gate#
24*12776SJames.McPherson@Sun.COM# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
250Sstevel@tonic-gate#
267078Smjnelson
277078Smjnelson#
283252Sdp# This script takes a file list and a workspace and builds a set of html files
293252Sdp# suitable for doing a code review of source changes via a web page.
303252Sdp# Documentation is available via the manual page, webrev.1, or just
313252Sdp# type 'webrev -h'.
320Sstevel@tonic-gate#
333252Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
343252Sdp# man page.
350Sstevel@tonic-gate#
363252Sdp
370Sstevel@tonic-gateREMOVED_COLOR=brown
380Sstevel@tonic-gateCHANGED_COLOR=blue
390Sstevel@tonic-gateNEW_COLOR=blue
400Sstevel@tonic-gate
413252SdpHTML='<?xml version="1.0"?>
423252Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
433252Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
443252Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
453252Sdp
463252SdpFRAMEHTML='<?xml version="1.0"?>
473252Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
483252Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
493252Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
503252Sdp
516922SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
526922Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
536922Smjnelson<meta http-equiv="Expires" content="-1"></meta>
543252Sdp<!--
553252Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
563252Sdp   to allow easy overriding by users of webrev via the userContent.css
573252Sdp   mechanism available in some browsers.
583252Sdp
593252Sdp   For example, to have all "removed" information be red instead of
603252Sdp   brown, set a rule in your userContent.css file like:
613252Sdp
623252Sdp       body#SUNWwebrev span.removed { color: red ! important; }
633252Sdp-->
643252Sdp<style type="text/css" media="screen">
653252Sdpbody {
663252Sdp    background-color: #eeeeee;
673252Sdp}
683252Sdphr {
693252Sdp    border: none 0;
703252Sdp    border-top: 1px solid #aaa;
713252Sdp    height: 1px;
723252Sdp}
733252Sdpdiv.summary {
743252Sdp    font-size: .8em;
753252Sdp    border-bottom: 1px solid #aaa;
763252Sdp    padding-left: 1em;
773252Sdp    padding-right: 1em;
783252Sdp}
793252Sdpdiv.summary h2 {
803252Sdp    margin-bottom: 0.3em;
813252Sdp}
823252Sdpdiv.summary table th {
833252Sdp    text-align: right;
843252Sdp    vertical-align: top;
853252Sdp    white-space: nowrap;
863252Sdp}
873252Sdpspan.lineschanged {
883252Sdp    font-size: 0.7em;
893252Sdp}
903252Sdpspan.oldmarker {
913252Sdp    color: red;
923252Sdp    font-size: large;
933252Sdp    font-weight: bold;
943252Sdp}
953252Sdpspan.newmarker {
963252Sdp    color: green;
973252Sdp    font-size: large;
983252Sdp    font-weight: bold;
993252Sdp}
1003252Sdpspan.removed {
1013252Sdp    color: brown;
1023252Sdp}
1033252Sdpspan.changed {
1043252Sdp    color: blue;
1053252Sdp}
1063252Sdpspan.new {
1073252Sdp    color: blue;
1083252Sdp    font-weight: bold;
1093252Sdp}
1107078Smjnelsonspan.chmod {
1117078Smjnelson    font-size: 0.7em;
1127078Smjnelson    color: #db7800;
1137078Smjnelson}
1143252Sdpa.print { font-size: x-small; }
1153252Sdpa:hover { background-color: #ffcc99; }
1163252Sdp</style>
1173252Sdp
1183252Sdp<style type="text/css" media="print">
1193252Sdppre { font-size: 0.8em; font-family: courier, monospace; }
1203252Sdpspan.removed { color: #444; font-style: italic }
1213252Sdpspan.changed { font-weight: bold; }
1223252Sdpspan.new { font-weight: bold; }
1233252Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
1243252Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
1253252Sdpa.print {display: none}
1263252Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
1273252Sdp</style>
1283252Sdp'
1293252Sdp
1303252Sdp#
1313252Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
1323252Sdp# want them to be bolded as we do in cdiffs or sdiffs).
1333252Sdp#
1343252SdpUDIFFCSS='
1353252Sdp<style type="text/css" media="screen">
1363252Sdpspan.new {
1373252Sdp    color: blue;
1383252Sdp    font-weight: normal;
1393252Sdp}
1403252Sdp</style>
1413252Sdp'
1423252Sdp
1439079SVladimir.Kotal@Sun.COM#
1449079SVladimir.Kotal@Sun.COM# Display remote target with prefix and trailing slash.
1459079SVladimir.Kotal@Sun.COM#
1469079SVladimir.Kotal@Sun.COMfunction print_upload_header
1479079SVladimir.Kotal@Sun.COM{
1489079SVladimir.Kotal@Sun.COM	typeset -r prefix=$1
1499079SVladimir.Kotal@Sun.COM	typeset display_target
1509079SVladimir.Kotal@Sun.COM
1519079SVladimir.Kotal@Sun.COM	if [[ -z $tflag ]]; then
1529079SVladimir.Kotal@Sun.COM		display_target=${prefix}${remote_target}
1539079SVladimir.Kotal@Sun.COM	else
1549079SVladimir.Kotal@Sun.COM		display_target=${remote_target}
1559079SVladimir.Kotal@Sun.COM	fi
1569079SVladimir.Kotal@Sun.COM
1579079SVladimir.Kotal@Sun.COM	if [[ ${display_target} != */ ]]; then
1589079SVladimir.Kotal@Sun.COM		display_target=${display_target}/
1599079SVladimir.Kotal@Sun.COM	fi
1609079SVladimir.Kotal@Sun.COM
1619079SVladimir.Kotal@Sun.COM	print "      Upload to: ${display_target}\n" \
1629079SVladimir.Kotal@Sun.COM	    "     Uploading: \c"
1639079SVladimir.Kotal@Sun.COM}
1649079SVladimir.Kotal@Sun.COM
1659079SVladimir.Kotal@Sun.COM#
1668018SVladimir.Kotal@Sun.COM# Upload the webrev via rsync. Return 0 on success, 1 on error.
1679079SVladimir.Kotal@Sun.COM#
1688365SVladimir.Kotal@Sun.COMfunction rsync_upload
1698018SVladimir.Kotal@Sun.COM{
1709079SVladimir.Kotal@Sun.COM	if (( $# != 2 )); then
1719079SVladimir.Kotal@Sun.COM		print "\nERROR: rsync_upload: wrong usage ($#)"
1729079SVladimir.Kotal@Sun.COM		exit 1
1739079SVladimir.Kotal@Sun.COM	fi
1749079SVladimir.Kotal@Sun.COM
1759079SVladimir.Kotal@Sun.COM	typeset -r dst=$1
1769079SVladimir.Kotal@Sun.COM	integer -r print_err_msg=$2
1779079SVladimir.Kotal@Sun.COM
1789079SVladimir.Kotal@Sun.COM	print_upload_header ${rsync_prefix}
1799079SVladimir.Kotal@Sun.COM	print "rsync ... \c"
1809503SVladimir.Kotal@Sun.COM	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
1819079SVladimir.Kotal@Sun.COM	if [[ -z $err_msg ]]; then
1829079SVladimir.Kotal@Sun.COM		print "\nERROR: rsync_upload: cannot create temporary file"
1838018SVladimir.Kotal@Sun.COM		return 1
1848018SVladimir.Kotal@Sun.COM	fi
1859079SVladimir.Kotal@Sun.COM	#
1869079SVladimir.Kotal@Sun.COM	# The source directory must end with a slash in order to copy just
1879079SVladimir.Kotal@Sun.COM	# directory contents, not the whole directory.
1889079SVladimir.Kotal@Sun.COM	#
1899079SVladimir.Kotal@Sun.COM	typeset src_dir=$WDIR
1909079SVladimir.Kotal@Sun.COM	if [[ ${src_dir} != */ ]]; then
1919079SVladimir.Kotal@Sun.COM		src_dir=${src_dir}/
1929079SVladimir.Kotal@Sun.COM	fi
1939079SVladimir.Kotal@Sun.COM	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
1948018SVladimir.Kotal@Sun.COM	if (( $? != 0 )); then
1959079SVladimir.Kotal@Sun.COM		if (( ${print_err_msg} > 0 )); then
1969079SVladimir.Kotal@Sun.COM			print "Failed.\nERROR: rsync failed"
1979079SVladimir.Kotal@Sun.COM			print "src dir: '${src_dir}'\ndst dir: '$dst'"
1989079SVladimir.Kotal@Sun.COM			print "error messages:"
1999079SVladimir.Kotal@Sun.COM			$SED 's/^/> /' $err_msg
2009079SVladimir.Kotal@Sun.COM			rm -f $err_msg
2019079SVladimir.Kotal@Sun.COM		fi
2028018SVladimir.Kotal@Sun.COM		return 1
2038018SVladimir.Kotal@Sun.COM	fi
2048018SVladimir.Kotal@Sun.COM
2059079SVladimir.Kotal@Sun.COM	rm -f $err_msg
2068018SVladimir.Kotal@Sun.COM	print "Done."
2078018SVladimir.Kotal@Sun.COM	return 0
2088018SVladimir.Kotal@Sun.COM}
2098018SVladimir.Kotal@Sun.COM
2109079SVladimir.Kotal@Sun.COM#
2119079SVladimir.Kotal@Sun.COM# Create directories on remote host using SFTP. Return 0 on success,
2129079SVladimir.Kotal@Sun.COM# 1 on failure.
2139079SVladimir.Kotal@Sun.COM#
2149079SVladimir.Kotal@Sun.COMfunction remote_mkdirs
2159079SVladimir.Kotal@Sun.COM{
2169079SVladimir.Kotal@Sun.COM	typeset -r dir_spec=$1
21711735SVladimir.Kotal@Sun.COM	typeset -r host_spec=$2
2189079SVladimir.Kotal@Sun.COM
2199079SVladimir.Kotal@Sun.COM	#
2209079SVladimir.Kotal@Sun.COM	# If the supplied path is absolute we assume all directories are
2219079SVladimir.Kotal@Sun.COM	# created, otherwise try to create all directories in the path
2229079SVladimir.Kotal@Sun.COM	# except the last one which will be created by scp.
2239079SVladimir.Kotal@Sun.COM	#
2249079SVladimir.Kotal@Sun.COM	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
2259079SVladimir.Kotal@Sun.COM		print "mkdirs \c"
2269079SVladimir.Kotal@Sun.COM		#
2279079SVladimir.Kotal@Sun.COM		# Remove the last directory from directory specification.
2289079SVladimir.Kotal@Sun.COM		#
2299079SVladimir.Kotal@Sun.COM		typeset -r dirs_mk=${dir_spec%/*}
2309503SVladimir.Kotal@Sun.COM		typeset -r batch_file_mkdir=$( $MKTEMP \
2319503SVladimir.Kotal@Sun.COM		    /tmp/webrev_mkdir.XXXXXX )
2329079SVladimir.Kotal@Sun.COM		if [[ -z $batch_file_mkdir ]]; then
2339079SVladimir.Kotal@Sun.COM			print "\nERROR: remote_mkdirs:" \
2349079SVladimir.Kotal@Sun.COM			    "cannot create temporary file for batch file"
2359079SVladimir.Kotal@Sun.COM			return 1
2369079SVladimir.Kotal@Sun.COM		fi
2379079SVladimir.Kotal@Sun.COM                OLDIFS=$IFS
2389079SVladimir.Kotal@Sun.COM                IFS=/
2399079SVladimir.Kotal@Sun.COM		typeset dir
2409079SVladimir.Kotal@Sun.COM                for dir in ${dirs_mk}; do
2419079SVladimir.Kotal@Sun.COM			#
2429079SVladimir.Kotal@Sun.COM			# Use the '-' prefix to ignore mkdir errors in order
2439079SVladimir.Kotal@Sun.COM			# to avoid an error in case the directory already
2449079SVladimir.Kotal@Sun.COM			# exists. We check the directory with chdir to be sure
2459079SVladimir.Kotal@Sun.COM			# there is one.
2469079SVladimir.Kotal@Sun.COM			#
2479079SVladimir.Kotal@Sun.COM                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
2489079SVladimir.Kotal@Sun.COM                        print "chdir ${dir}" >> ${batch_file_mkdir}
2499079SVladimir.Kotal@Sun.COM                done
2509079SVladimir.Kotal@Sun.COM                IFS=$OLDIFS
2519503SVladimir.Kotal@Sun.COM		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
2529079SVladimir.Kotal@Sun.COM		if [[ -z ${sftp_err_msg} ]]; then
2539079SVladimir.Kotal@Sun.COM			print "\nERROR: remote_mkdirs:" \
2549079SVladimir.Kotal@Sun.COM			    "cannot create temporary file for error messages"
2559079SVladimir.Kotal@Sun.COM			return 1
2569079SVladimir.Kotal@Sun.COM		fi
2579079SVladimir.Kotal@Sun.COM		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
2589079SVladimir.Kotal@Sun.COM		if (( $? != 0 )); then
2599079SVladimir.Kotal@Sun.COM			print "\nERROR: failed to create remote directories"
2609079SVladimir.Kotal@Sun.COM			print "error messages:"
2619079SVladimir.Kotal@Sun.COM			$SED 's/^/> /' ${sftp_err_msg}
2629079SVladimir.Kotal@Sun.COM			rm -f ${sftp_err_msg} ${batch_file_mkdir}
2639079SVladimir.Kotal@Sun.COM			return 1
2649079SVladimir.Kotal@Sun.COM		fi
2659079SVladimir.Kotal@Sun.COM		rm -f ${sftp_err_msg} ${batch_file_mkdir}
2669079SVladimir.Kotal@Sun.COM	fi
2679079SVladimir.Kotal@Sun.COM
2689079SVladimir.Kotal@Sun.COM	return 0
2699079SVladimir.Kotal@Sun.COM}
2709079SVladimir.Kotal@Sun.COM
2719079SVladimir.Kotal@Sun.COM#
2728018SVladimir.Kotal@Sun.COM# Upload the webrev via SSH. Return 0 on success, 1 on error.
2739079SVladimir.Kotal@Sun.COM#
2748365SVladimir.Kotal@Sun.COMfunction ssh_upload
2758018SVladimir.Kotal@Sun.COM{
2768018SVladimir.Kotal@Sun.COM	if (( $# != 1 )); then
2779079SVladimir.Kotal@Sun.COM		print "\nERROR: ssh_upload: wrong number of arguments"
2789079SVladimir.Kotal@Sun.COM		exit 1
2798018SVladimir.Kotal@Sun.COM	fi
2808018SVladimir.Kotal@Sun.COM
2818018SVladimir.Kotal@Sun.COM	typeset dst=$1
2828018SVladimir.Kotal@Sun.COM	typeset -r host_spec=${dst%%:*}
2838365SVladimir.Kotal@Sun.COM	typeset -r dir_spec=${dst#*:}
2848365SVladimir.Kotal@Sun.COM
2859079SVladimir.Kotal@Sun.COM	#
2869079SVladimir.Kotal@Sun.COM	# Display the upload information before calling delete_webrev
2879079SVladimir.Kotal@Sun.COM	# because it will also print its progress.
2889079SVladimir.Kotal@Sun.COM	#
2899079SVladimir.Kotal@Sun.COM	print_upload_header ${ssh_prefix}
2909079SVladimir.Kotal@Sun.COM
2919079SVladimir.Kotal@Sun.COM	#
2929079SVladimir.Kotal@Sun.COM	# If the deletion was explicitly requested there is no need
2939079SVladimir.Kotal@Sun.COM	# to perform it again.
2949079SVladimir.Kotal@Sun.COM	#
2958365SVladimir.Kotal@Sun.COM	if [[ -z $Dflag ]]; then
2969079SVladimir.Kotal@Sun.COM		#
2979079SVladimir.Kotal@Sun.COM		# We do not care about return value because this might be
2989079SVladimir.Kotal@Sun.COM		# the first time this directory is uploaded.
2999079SVladimir.Kotal@Sun.COM		#
3008365SVladimir.Kotal@Sun.COM		delete_webrev 0
3018018SVladimir.Kotal@Sun.COM	fi
3028018SVladimir.Kotal@Sun.COM
3039079SVladimir.Kotal@Sun.COM	#
3049079SVladimir.Kotal@Sun.COM	# Create remote directories. Any error reporting will be done
3059079SVladimir.Kotal@Sun.COM	# in remote_mkdirs function.
3069079SVladimir.Kotal@Sun.COM	#
30711735SVladimir.Kotal@Sun.COM	remote_mkdirs ${dir_spec} ${host_spec}
3088018SVladimir.Kotal@Sun.COM	if (( $? != 0 )); then
3098018SVladimir.Kotal@Sun.COM		return 1
3108018SVladimir.Kotal@Sun.COM	fi
3118018SVladimir.Kotal@Sun.COM
3129079SVladimir.Kotal@Sun.COM	print "upload ... \c"
3139503SVladimir.Kotal@Sun.COM	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
3149079SVladimir.Kotal@Sun.COM	if [[ -z ${scp_err_msg} ]]; then
3159079SVladimir.Kotal@Sun.COM		print "\nERROR: ssh_upload:" \
3169079SVladimir.Kotal@Sun.COM		    "cannot create temporary file for error messages"
3179079SVladimir.Kotal@Sun.COM		return 1
3189079SVladimir.Kotal@Sun.COM	fi
3199079SVladimir.Kotal@Sun.COM	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
3209079SVladimir.Kotal@Sun.COM		$WDIR $dst 2>${scp_err_msg}
3219079SVladimir.Kotal@Sun.COM	if (( $? != 0 )); then
3229079SVladimir.Kotal@Sun.COM		print "Failed.\nERROR: scp failed"
3239079SVladimir.Kotal@Sun.COM		print "src dir: '$WDIR'\ndst dir: '$dst'"
3249079SVladimir.Kotal@Sun.COM		print "error messages:"
3259079SVladimir.Kotal@Sun.COM		$SED 's/^/> /' ${scp_err_msg}
3269079SVladimir.Kotal@Sun.COM		rm -f ${scp_err_msg}
3279079SVladimir.Kotal@Sun.COM		return 1
3289079SVladimir.Kotal@Sun.COM	fi
3299079SVladimir.Kotal@Sun.COM
3309079SVladimir.Kotal@Sun.COM	rm -f ${scp_err_msg}
3318018SVladimir.Kotal@Sun.COM	print "Done."
3328018SVladimir.Kotal@Sun.COM	return 0
3338018SVladimir.Kotal@Sun.COM}
3348018SVladimir.Kotal@Sun.COM
3358018SVladimir.Kotal@Sun.COM#
3368365SVladimir.Kotal@Sun.COM# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
3379079SVladimir.Kotal@Sun.COM# on failure. If first argument is 1 then perform the check of sftp return
3389079SVladimir.Kotal@Sun.COM# value otherwise ignore it. If second argument is present it means this run
3399079SVladimir.Kotal@Sun.COM# only performs deletion.
3408365SVladimir.Kotal@Sun.COM#
3418365SVladimir.Kotal@Sun.COMfunction delete_webrev
3428365SVladimir.Kotal@Sun.COM{
3439079SVladimir.Kotal@Sun.COM	if (( $# < 1 )); then
3449079SVladimir.Kotal@Sun.COM		print "delete_webrev: wrong number of arguments"
3459079SVladimir.Kotal@Sun.COM		exit 1
3468365SVladimir.Kotal@Sun.COM	fi
3478365SVladimir.Kotal@Sun.COM
3489079SVladimir.Kotal@Sun.COM	integer -r check=$1
3499079SVladimir.Kotal@Sun.COM	integer delete_only=0
3509079SVladimir.Kotal@Sun.COM	if (( $# == 2 )); then
3519079SVladimir.Kotal@Sun.COM		delete_only=1
3529079SVladimir.Kotal@Sun.COM	fi
3539079SVladimir.Kotal@Sun.COM
3549079SVladimir.Kotal@Sun.COM	#
3558365SVladimir.Kotal@Sun.COM	# Strip the transport specification part of remote target first.
3569079SVladimir.Kotal@Sun.COM	#
3578365SVladimir.Kotal@Sun.COM	typeset -r stripped_target=${remote_target##*://}
3588365SVladimir.Kotal@Sun.COM	typeset -r host_spec=${stripped_target%%:*}
3598365SVladimir.Kotal@Sun.COM	typeset -r dir_spec=${stripped_target#*:}
3608365SVladimir.Kotal@Sun.COM	typeset dir_rm
3618365SVladimir.Kotal@Sun.COM
3629079SVladimir.Kotal@Sun.COM	#
3638365SVladimir.Kotal@Sun.COM	# Do not accept an absolute path.
3649079SVladimir.Kotal@Sun.COM	#
3658365SVladimir.Kotal@Sun.COM	if [[ ${dir_spec} == /* ]]; then
3668365SVladimir.Kotal@Sun.COM		return 1
3678365SVladimir.Kotal@Sun.COM	fi
3688365SVladimir.Kotal@Sun.COM
3699079SVladimir.Kotal@Sun.COM	#
3708365SVladimir.Kotal@Sun.COM	# Strip the ending slash.
3719079SVladimir.Kotal@Sun.COM	#
3728365SVladimir.Kotal@Sun.COM	if [[ ${dir_spec} == */ ]]; then
3738365SVladimir.Kotal@Sun.COM		dir_rm=${dir_spec%%/}
3748365SVladimir.Kotal@Sun.COM	else
3758365SVladimir.Kotal@Sun.COM		dir_rm=${dir_spec}
3768365SVladimir.Kotal@Sun.COM	fi
3778365SVladimir.Kotal@Sun.COM
3789079SVladimir.Kotal@Sun.COM	if (( ${delete_only} > 0 )); then
3799079SVladimir.Kotal@Sun.COM		print "       Removing: \c"
3809079SVladimir.Kotal@Sun.COM	else
3819079SVladimir.Kotal@Sun.COM		print "rmdir \c"
3829079SVladimir.Kotal@Sun.COM	fi
3838365SVladimir.Kotal@Sun.COM	if [[ -z "$dir_rm" ]]; then
3849079SVladimir.Kotal@Sun.COM		print "\nERROR: empty directory for removal"
3858365SVladimir.Kotal@Sun.COM		return 1
3868365SVladimir.Kotal@Sun.COM	fi
3878365SVladimir.Kotal@Sun.COM
3889079SVladimir.Kotal@Sun.COM	#
3898365SVladimir.Kotal@Sun.COM	# Prepare batch file.
3909079SVladimir.Kotal@Sun.COM	#
3919503SVladimir.Kotal@Sun.COM	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
3928365SVladimir.Kotal@Sun.COM	if [[ -z $batch_file_rm ]]; then
3939079SVladimir.Kotal@Sun.COM		print "\nERROR: delete_webrev: cannot create temporary file"
3948365SVladimir.Kotal@Sun.COM		return 1
3958365SVladimir.Kotal@Sun.COM	fi
3968365SVladimir.Kotal@Sun.COM	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
3978365SVladimir.Kotal@Sun.COM
3989079SVladimir.Kotal@Sun.COM	#
3998365SVladimir.Kotal@Sun.COM	# Perform remote deletion and remove the batch file.
4009079SVladimir.Kotal@Sun.COM	#
4019503SVladimir.Kotal@Sun.COM	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
4029079SVladimir.Kotal@Sun.COM	if [[ -z ${sftp_err_msg} ]]; then
4039079SVladimir.Kotal@Sun.COM		print "\nERROR: delete_webrev:" \
4049079SVladimir.Kotal@Sun.COM		    "cannot create temporary file for error messages"
4059079SVladimir.Kotal@Sun.COM		return 1
4069079SVladimir.Kotal@Sun.COM	fi
4079079SVladimir.Kotal@Sun.COM	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
4088365SVladimir.Kotal@Sun.COM	integer -r ret=$?
4098365SVladimir.Kotal@Sun.COM	rm -f $batch_file_rm
4108365SVladimir.Kotal@Sun.COM	if (( $ret != 0 && $check > 0 )); then
4119079SVladimir.Kotal@Sun.COM		print "Failed.\nERROR: failed to remove remote directories"
4129079SVladimir.Kotal@Sun.COM		print "error messages:"
4139079SVladimir.Kotal@Sun.COM		$SED 's/^/> /' ${sftp_err_msg}
4149079SVladimir.Kotal@Sun.COM		rm -f ${sftp_err_msg}
4158365SVladimir.Kotal@Sun.COM		return $ret
4168365SVladimir.Kotal@Sun.COM	fi
4179079SVladimir.Kotal@Sun.COM	rm -f ${sftp_err_msg}
4189079SVladimir.Kotal@Sun.COM	if (( ${delete_only} > 0 )); then
4199079SVladimir.Kotal@Sun.COM		print "Done."
4209079SVladimir.Kotal@Sun.COM	fi
4218365SVladimir.Kotal@Sun.COM
4228365SVladimir.Kotal@Sun.COM	return 0
4238365SVladimir.Kotal@Sun.COM}
4248365SVladimir.Kotal@Sun.COM
4258365SVladimir.Kotal@Sun.COM#
4268018SVladimir.Kotal@Sun.COM# Upload webrev to remote site
4278018SVladimir.Kotal@Sun.COM#
4288365SVladimir.Kotal@Sun.COMfunction upload_webrev
4298018SVladimir.Kotal@Sun.COM{
4309079SVladimir.Kotal@Sun.COM	integer ret
4318018SVladimir.Kotal@Sun.COM
4328018SVladimir.Kotal@Sun.COM	if [[ ! -d "$WDIR" ]]; then
4339079SVladimir.Kotal@Sun.COM		print "\nERROR: webrev directory '$WDIR' does not exist"
4348018SVladimir.Kotal@Sun.COM		return 1
4358018SVladimir.Kotal@Sun.COM	fi
4368018SVladimir.Kotal@Sun.COM
4379079SVladimir.Kotal@Sun.COM	#
4388018SVladimir.Kotal@Sun.COM	# Perform a late check to make sure we do not upload closed source
4398018SVladimir.Kotal@Sun.COM	# to remote target when -n is used. If the user used custom remote
4408018SVladimir.Kotal@Sun.COM	# target he probably knows what he is doing.
4419079SVladimir.Kotal@Sun.COM	#
4428018SVladimir.Kotal@Sun.COM	if [[ -n $nflag && -z $tflag ]]; then
4438365SVladimir.Kotal@Sun.COM		$FIND $WDIR -type d -name closed \
4448018SVladimir.Kotal@Sun.COM			| $GREP closed >/dev/null
4458018SVladimir.Kotal@Sun.COM		if (( $? == 0 )); then
4469079SVladimir.Kotal@Sun.COM			print "\nERROR: directory '$WDIR' contains" \
4479079SVladimir.Kotal@Sun.COM			    "\"closed\" directory"
4488018SVladimir.Kotal@Sun.COM			return 1
4498018SVladimir.Kotal@Sun.COM		fi
4508018SVladimir.Kotal@Sun.COM	fi
4518018SVladimir.Kotal@Sun.COM
4529079SVladimir.Kotal@Sun.COM
4539079SVladimir.Kotal@Sun.COM	#
4549079SVladimir.Kotal@Sun.COM	# We have the URI for remote destination now so let's start the upload.
4559079SVladimir.Kotal@Sun.COM	#
4568018SVladimir.Kotal@Sun.COM	if [[ -n $tflag ]]; then
4578018SVladimir.Kotal@Sun.COM		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
4589079SVladimir.Kotal@Sun.COM			rsync_upload ${remote_target##$rsync_prefix} 1
4599079SVladimir.Kotal@Sun.COM			ret=$?
4609079SVladimir.Kotal@Sun.COM			return $ret
4618018SVladimir.Kotal@Sun.COM		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
4628018SVladimir.Kotal@Sun.COM			ssh_upload ${remote_target##$ssh_prefix}
4639079SVladimir.Kotal@Sun.COM			ret=$?
4649079SVladimir.Kotal@Sun.COM			return $ret
4658018SVladimir.Kotal@Sun.COM		fi
4668018SVladimir.Kotal@Sun.COM	else
4679079SVladimir.Kotal@Sun.COM		#
4689079SVladimir.Kotal@Sun.COM		# Try rsync first and fallback to SSH in case it fails.
4699079SVladimir.Kotal@Sun.COM		#
4709079SVladimir.Kotal@Sun.COM		rsync_upload ${remote_target} 0
4719079SVladimir.Kotal@Sun.COM		ret=$?
4729079SVladimir.Kotal@Sun.COM		if (( $ret != 0 )); then
4739079SVladimir.Kotal@Sun.COM			print "Failed. (falling back to SSH)"
4748365SVladimir.Kotal@Sun.COM			ssh_upload ${remote_target}
4759079SVladimir.Kotal@Sun.COM			ret=$?
4768018SVladimir.Kotal@Sun.COM		fi
4779079SVladimir.Kotal@Sun.COM		return $ret
4788018SVladimir.Kotal@Sun.COM	fi
4798018SVladimir.Kotal@Sun.COM}
4808018SVladimir.Kotal@Sun.COM
4813252Sdp#
4829011SLubomir.Sedlacik@Sun.COM# input_cmd | url_encode | output_cmd
4839011SLubomir.Sedlacik@Sun.COM#
4849011SLubomir.Sedlacik@Sun.COM# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
4859011SLubomir.Sedlacik@Sun.COM#
4869011SLubomir.Sedlacik@Sun.COM# Reserved characters are: :/?#[]@!$&'()*+,;=
4879011SLubomir.Sedlacik@Sun.COM#
4889011SLubomir.Sedlacik@Sun.COM# While not a reserved character itself, percent '%' is reserved by definition
4899011SLubomir.Sedlacik@Sun.COM# so encode it first to avoid recursive transformation, and skip '/' which is
4909011SLubomir.Sedlacik@Sun.COM# a path delimiter.
4919011SLubomir.Sedlacik@Sun.COM#
4929561SVladimir.Kotal@Sun.COM# The quotation character is deliberately not escaped in order to make
4939561SVladimir.Kotal@Sun.COM# the substitution work with GNU sed.
4949561SVladimir.Kotal@Sun.COM#
4959011SLubomir.Sedlacik@Sun.COMfunction url_encode
4969011SLubomir.Sedlacik@Sun.COM{
4979079SVladimir.Kotal@Sun.COM	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
4989011SLubomir.Sedlacik@Sun.COM	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
4999011SLubomir.Sedlacik@Sun.COM	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
5009011SLubomir.Sedlacik@Sun.COM	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
5019561SVladimir.Kotal@Sun.COM	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
5029011SLubomir.Sedlacik@Sun.COM	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
5039011SLubomir.Sedlacik@Sun.COM}
5049011SLubomir.Sedlacik@Sun.COM
5059011SLubomir.Sedlacik@Sun.COM#
5063252Sdp# input_cmd | html_quote | output_cmd
5073252Sdp# or
5083252Sdp# html_quote filename | output_cmd
5090Sstevel@tonic-gate#
5100Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5110Sstevel@tonic-gate#
5120Sstevel@tonic-gatehtml_quote()
5130Sstevel@tonic-gate{
5149079SVladimir.Kotal@Sun.COM	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5150Sstevel@tonic-gate}
5160Sstevel@tonic-gate
5173252Sdp#
5189193SMark.J.Nelson@Sun.COM# input_cmd | its2url | output_cmd
5193252Sdp#
5209193SMark.J.Nelson@Sun.COM# Scan for information tracking system references and insert <a> links to the
5219193SMark.J.Nelson@Sun.COM# relevant databases.
5220Sstevel@tonic-gate#
5239193SMark.J.Nelson@Sun.COMits2url()
5243252Sdp{
5259193SMark.J.Nelson@Sun.COM	$SED -f ${its_sed_script}
5263252Sdp}
5273252Sdp
5283252Sdp#
5293252Sdp# strip_unchanged <infile> | output_cmd
5300Sstevel@tonic-gate#
5313252Sdp# Removes chunks of sdiff documents that have not changed. This makes it
5323252Sdp# easier for a code reviewer to find the bits that have changed.
5333252Sdp#
5343252Sdp# Deleted lines of text are replaced by a horizontal rule. Some
5353252Sdp# identical lines are retained before and after the changed lines to
5363252Sdp# provide some context.  The number of these lines is controlled by the
5377078Smjnelson# variable C in the $AWK script below.
5383252Sdp#
5393252Sdp# The script detects changed lines as any line that has a "<span class="
5403252Sdp# string embedded (unchanged lines have no particular class and are not
5413252Sdp# part of a <span>).  Blank lines (without a sequence number) are also
5423252Sdp# detected since they flag lines that have been inserted or deleted.
5430Sstevel@tonic-gate#
5443252Sdpstrip_unchanged()
5453252Sdp{
5467078Smjnelson	$AWK '
5473252Sdp	BEGIN	{ C = c = 20 }
5487078Smjnelson	NF == 0 || /<span class="/ {
5493252Sdp		if (c > C) {
5503252Sdp			c -= C
5513252Sdp			inx = 0
5523252Sdp			if (c > C) {
5536922Smjnelson				print "\n</pre><hr></hr><pre>"
5543252Sdp				inx = c % C
5553252Sdp				c = C
5563252Sdp			}
5573252Sdp
5583252Sdp			for (i = 0; i < c; i++)
5593252Sdp				print ln[(inx + i) % C]
5603252Sdp		}
5613252Sdp		c = 0;
5623252Sdp		print
5633252Sdp		next
5643252Sdp	}
5653252Sdp	{	if (c >= C) {
5663252Sdp			ln[c % C] = $0
5673252Sdp			c++;
5683252Sdp			next;
5693252Sdp		}
5703252Sdp		c++;
5713252Sdp		print
5723252Sdp	}
5736922Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
5743252Sdp
5753252Sdp	' $1
5763252Sdp}
5773252Sdp
5780Sstevel@tonic-gate#
5793252Sdp# sdiff_to_html
5803252Sdp#
5813252Sdp# This function takes two files as arguments, obtains their diff, and
5823252Sdp# processes the diff output to present the files as an HTML document with
5833252Sdp# the files displayed side-by-side, differences shown in color.  It also
5843252Sdp# takes a delta comment, rendered as an HTML snippet, as the third
5853252Sdp# argument.  The function takes two files as arguments, then the name of
5863252Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
5873252Sdp# e.g.
5880Sstevel@tonic-gate#
5893252Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
5903252Sdp#         new/usr/src/tools/scripts/webrev.sh \
5913252Sdp#         webrev.sh usr/src/tools/scripts \
5923252Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
5933252Sdp#          1234567</a> my bugid' > <file>.html
5943252Sdp#
5953252Sdp# framed_sdiff() is then called which creates $2.frames.html
5963252Sdp# in the webrev tree.
5973252Sdp#
5983252Sdp# FYI: This function is rather unusual in its use of awk.  The initial
5993252Sdp# diff run produces conventional diff output showing changed lines mixed
6003252Sdp# with editing codes.  The changed lines are ignored - we're interested in
6013252Sdp# the editing codes, e.g.
6020Sstevel@tonic-gate#
6030Sstevel@tonic-gate#      8c8
6040Sstevel@tonic-gate#      57a61
6050Sstevel@tonic-gate#      63c66,76
6060Sstevel@tonic-gate#      68,93d80
6070Sstevel@tonic-gate#      106d90
6080Sstevel@tonic-gate#      108,110d91
6090Sstevel@tonic-gate#
6103252Sdp#  These editing codes are parsed by the awk script and used to generate
6113252Sdp#  another awk script that generates HTML, e.g the above lines would turn
6123252Sdp#  into something like this:
6130Sstevel@tonic-gate#
6140Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6150Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
6163252Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6170Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6180Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6190Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6200Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6210Sstevel@tonic-gate#        :               :
6220Sstevel@tonic-gate#
6233252Sdp#  This script is then run on the original source file to generate the
6243252Sdp#  HTML that corresponds to the source file.
6250Sstevel@tonic-gate#
6263252Sdp#  The two HTML files are then combined into a single piece of HTML that
6273252Sdp#  uses an HTML table construct to present the files side by side.  You'll
6283252Sdp#  notice that the changes are color-coded:
6290Sstevel@tonic-gate#
6300Sstevel@tonic-gate#   black     - unchanged lines
6310Sstevel@tonic-gate#   blue      - changed lines
6320Sstevel@tonic-gate#   bold blue - new lines
6330Sstevel@tonic-gate#   brown     - deleted lines
6340Sstevel@tonic-gate#
6353252Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
6363252Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
6373252Sdp#  Teamware's filemerge tool.
6383252Sdp#
6393252Sdpsdiff_to_html()
6403252Sdp{
6413252Sdp	diff -b $1 $2 > /tmp/$$.diffs
6420Sstevel@tonic-gate
6433252Sdp	TNAME=$3
6443252Sdp	TPATH=$4
6453252Sdp	COMMENT=$5
6460Sstevel@tonic-gate
6473252Sdp	#
6483252Sdp	#  Now we have the diffs, generate the HTML for the old file.
6493252Sdp	#
6507078Smjnelson	$AWK '
6513252Sdp	BEGIN	{
6523252Sdp		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
6533252Sdp		printf "function removed() "
6543252Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
6553252Sdp		printf "function changed() "
6563252Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
6573252Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
6583252Sdp}
6593252Sdp	/^</	{next}
6603252Sdp	/^>/	{next}
6613252Sdp	/^---/	{next}
6620Sstevel@tonic-gate
6633252Sdp	{
6640Sstevel@tonic-gate	split($1, a, /[cad]/) ;
6650Sstevel@tonic-gate	if (index($1, "a")) {
6660Sstevel@tonic-gate		if (a[1] == 0) {
6670Sstevel@tonic-gate			n = split(a[2], r, /,/);
6680Sstevel@tonic-gate			if (n == 1)
6690Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
6700Sstevel@tonic-gate			else
6710Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
6720Sstevel@tonic-gate				(r[2] - r[1]) + 1
6730Sstevel@tonic-gate			next
6740Sstevel@tonic-gate		}
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
6770Sstevel@tonic-gate		n = split(a[2], r, /,/);
6780Sstevel@tonic-gate		s = r[1];
6790Sstevel@tonic-gate		if (n == 1)
6800Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
6810Sstevel@tonic-gate		else {
6820Sstevel@tonic-gate			n = r[2] - r[1]
6830Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
6840Sstevel@tonic-gate			(r[2] - r[1]) + 1
6850Sstevel@tonic-gate		}
6863252Sdp		next
6870Sstevel@tonic-gate	}
6880Sstevel@tonic-gate	if (index($1, "d")) {
6890Sstevel@tonic-gate		n = split(a[1], r, /,/);
6900Sstevel@tonic-gate		n1 = r[1]
6910Sstevel@tonic-gate		n2 = r[2]
6920Sstevel@tonic-gate		if (n == 1)
6933252Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
6940Sstevel@tonic-gate		else
6953252Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
6963252Sdp		next
6970Sstevel@tonic-gate	}
6980Sstevel@tonic-gate	if (index($1, "c")) {
6990Sstevel@tonic-gate		n = split(a[1], r, /,/);
7000Sstevel@tonic-gate		n1 = r[1]
7010Sstevel@tonic-gate		n2 = r[2]
7020Sstevel@tonic-gate		final = n2
7030Sstevel@tonic-gate		d1 = 0
7040Sstevel@tonic-gate		if (n == 1)
7053252Sdp			printf "NR==%s\t\t{changed();" , n1
7060Sstevel@tonic-gate		else {
7070Sstevel@tonic-gate			d1 = n2 - n1
7083252Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7090Sstevel@tonic-gate		}
7100Sstevel@tonic-gate		m = split(a[2], r, /,/);
7110Sstevel@tonic-gate		n1 = r[1]
7120Sstevel@tonic-gate		n2 = r[2]
7130Sstevel@tonic-gate		if (m > 1) {
7140Sstevel@tonic-gate			d2  = n2 - n1
7150Sstevel@tonic-gate			if (d2 > d1) {
7160Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7170Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7180Sstevel@tonic-gate			}
7190Sstevel@tonic-gate		}
7200Sstevel@tonic-gate		printf "next}\n" ;
7213252Sdp
7223252Sdp		next
7233252Sdp	}
7240Sstevel@tonic-gate	}
7250Sstevel@tonic-gate
7263252Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
7273252Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7280Sstevel@tonic-gate
7293252Sdp	#
7303252Sdp	#  Now generate the HTML for the new file
7313252Sdp	#
7327078Smjnelson	$AWK '
7333252Sdp	BEGIN	{
7343252Sdp		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
7353252Sdp		printf "function new() "
7363252Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
7373252Sdp		printf "function changed() "
7383252Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
7393252Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7403252Sdp	}
7410Sstevel@tonic-gate
7423252Sdp	/^</	{next}
7433252Sdp	/^>/	{next}
7443252Sdp	/^---/	{next}
7453252Sdp
7463252Sdp	{
7470Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7480Sstevel@tonic-gate	if (index($1, "d")) {
7490Sstevel@tonic-gate		if (a[2] == 0) {
7500Sstevel@tonic-gate			n = split(a[1], r, /,/);
7510Sstevel@tonic-gate			if (n == 1)
7520Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7530Sstevel@tonic-gate			else
7540Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7550Sstevel@tonic-gate				(r[2] - r[1]) + 1
7560Sstevel@tonic-gate			next
7570Sstevel@tonic-gate		}
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
7600Sstevel@tonic-gate		n = split(a[1], r, /,/);
7610Sstevel@tonic-gate		s = r[1];
7620Sstevel@tonic-gate		if (n == 1)
7630Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7640Sstevel@tonic-gate		else {
7650Sstevel@tonic-gate			n = r[2] - r[1]
7660Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7670Sstevel@tonic-gate			(r[2] - r[1]) + 1
7680Sstevel@tonic-gate		}
7693252Sdp		next
7700Sstevel@tonic-gate	}
7710Sstevel@tonic-gate	if (index($1, "a")) {
7720Sstevel@tonic-gate		n = split(a[2], r, /,/);
7730Sstevel@tonic-gate		n1 = r[1]
7740Sstevel@tonic-gate		n2 = r[2]
7750Sstevel@tonic-gate		if (n == 1)
7763252Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
7770Sstevel@tonic-gate		else
7783252Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
7793252Sdp		next
7800Sstevel@tonic-gate	}
7810Sstevel@tonic-gate	if (index($1, "c")) {
7820Sstevel@tonic-gate		n = split(a[2], r, /,/);
7830Sstevel@tonic-gate		n1 = r[1]
7840Sstevel@tonic-gate		n2 = r[2]
7850Sstevel@tonic-gate		final = n2
7860Sstevel@tonic-gate		d2 = 0;
7870Sstevel@tonic-gate		if (n == 1) {
7880Sstevel@tonic-gate			final = n1
7893252Sdp			printf "NR==%s\t\t{changed();" , n1
7900Sstevel@tonic-gate		} else {
7910Sstevel@tonic-gate			d2 = n2 - n1
7923252Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7930Sstevel@tonic-gate		}
7940Sstevel@tonic-gate		m = split(a[1], r, /,/);
7950Sstevel@tonic-gate		n1 = r[1]
7960Sstevel@tonic-gate		n2 = r[2]
7970Sstevel@tonic-gate		if (m > 1) {
7980Sstevel@tonic-gate			d1  = n2 - n1
7990Sstevel@tonic-gate			if (d1 > d2) {
8000Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8010Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8020Sstevel@tonic-gate			}
8030Sstevel@tonic-gate		}
8040Sstevel@tonic-gate		printf "next}\n" ;
8053252Sdp		next
8063252Sdp	}
8070Sstevel@tonic-gate	}
8083252Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8093252Sdp	' /tmp/$$.diffs > /tmp/$$.file2
8100Sstevel@tonic-gate
8113252Sdp	#
8127078Smjnelson	# Post-process the HTML files by running them back through $AWK
8133252Sdp	#
8147078Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8157078Smjnelson
8167078Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8170Sstevel@tonic-gate
8183252Sdp	#
8193252Sdp	# Now combine into a valid HTML file and side-by-side into a table
8203252Sdp	#
8213252Sdp	print "$HTML<head>$STDHEAD"
8227078Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
8233252Sdp	print "</head><body id=\"SUNWwebrev\">"
8243252Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
8253252Sdp	print "<pre>$COMMENT</pre>\n"
8263252Sdp	print "<table><tr valign=\"top\">"
8273252Sdp	print "<td><pre>"
8280Sstevel@tonic-gate
8293252Sdp	strip_unchanged /tmp/$$.file1.html
8300Sstevel@tonic-gate
8313252Sdp	print "</pre></td><td><pre>"
8323252Sdp
8333252Sdp	strip_unchanged /tmp/$$.file2.html
8340Sstevel@tonic-gate
8353252Sdp	print "</pre></td>"
8363252Sdp	print "</tr></table>"
8373252Sdp	print "</body></html>"
8380Sstevel@tonic-gate
8393252Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
8403252Sdp	    "$COMMENT"
8410Sstevel@tonic-gate}
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate
8443252Sdp#
8453252Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
8463252Sdp#
8473252Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
8483252Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
8493252Sdp# and then emit the main frame.  Content is placed into:
8503252Sdp#
8513252Sdp#    $WDIR/DIR/$TNAME.lhs.html
8523252Sdp#    $WDIR/DIR/$TNAME.rhs.html
8533252Sdp#    $WDIR/DIR/$TNAME.frames.html
8543252Sdp#
8553252Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
8563252Sdp#
8570Sstevel@tonic-gatefunction framed_sdiff
8580Sstevel@tonic-gate{
8593252Sdp	typeset TNAME=$1
8603252Sdp	typeset TPATH=$2
8613252Sdp	typeset lhsfile=$3
8623252Sdp	typeset rhsfile=$4
8633252Sdp	typeset comments=$5
8643252Sdp	typeset RTOP
8653252Sdp
8663252Sdp	# Enable html files to access WDIR via a relative path.
8673252Sdp	RTOP=$(relative_dir $TPATH $WDIR)
8683252Sdp
8693252Sdp	# Make the rhs/lhs files and output the frameset file.
8703252Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
8713252Sdp
8723252Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
8739191SMark.J.Nelson@Sun.COM	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
8743252Sdp	    </head>
8753252Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
8766922Smjnelson	    <a name="0"></a>
8776922Smjnelson	    <pre>$comments</pre><hr></hr>
8783252Sdp	EOF
8793252Sdp
8803252Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
8813252Sdp
8823252Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
8833252Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
8843252Sdp
8853252Sdp	close='</body></html>'
8863252Sdp
8873252Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
8883252Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
8893252Sdp
8903252Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
8913252Sdp	print "<title>$WNAME Framed-Sdiff " \
8923252Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
8933252Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
8943252Sdp	  <frameset rows="*,60">
8953252Sdp	    <frameset cols="50%,50%">
8966922Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
8976922Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
8983252Sdp	    </frameset>
8999191SMark.J.Nelson@Sun.COM	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
9006922Smjnelson	   marginheight="0" name="nav"></frame>
9013252Sdp	  <noframes>
9023252Sdp            <body id="SUNWwebrev">
9033252Sdp	      Alas 'frames' webrev requires that your browser supports frames
9043252Sdp	      and has the feature enabled.
9053252Sdp            </body>
9063252Sdp	  </noframes>
9073252Sdp	  </frameset>
9080Sstevel@tonic-gate	</html>
9090Sstevel@tonic-gate	EOF
9100Sstevel@tonic-gate}
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate
9133252Sdp#
9143252Sdp# fix_postscript
9150Sstevel@tonic-gate#
9163252Sdp# Merge codereview output files to a single conforming postscript file, by:
91710789SEdward.Pilatowicz@Sun.COM#	- removing all extraneous headers/trailers
9183252Sdp#	- making the page numbers right
9193252Sdp#	- removing pages devoid of contents which confuse some
9203252Sdp#	  postscript readers.
9213252Sdp#
9223252Sdp# From Casper.
9230Sstevel@tonic-gate#
9243252Sdpfunction fix_postscript
9253252Sdp{
9263252Sdp	infile=$1
9273252Sdp
9283252Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9290Sstevel@tonic-gate
9303252Sdp	print scalar(<>);		# %!PS-Adobe---
9313252Sdp	print "%%Orientation: Landscape\n";
9323252Sdp
9333252Sdp	$pno = 0;
9343252Sdp	$doprint = 1;
9353252Sdp
9363252Sdp	$page = "";
9370Sstevel@tonic-gate
9383252Sdp	while (<>) {
9393252Sdp		next if (/^%%Pages:\s*\d+/);
9403252Sdp
9413252Sdp		if (/^%%Page:/) {
9423252Sdp			if ($pno == 0 || $page =~ /\)S/) {
9433252Sdp				# Header or single page containing text
9443252Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
9453252Sdp				print $page;
9463252Sdp				$pno++;
9473252Sdp			} else {
9483252Sdp				# Empty page, skip it.
9493252Sdp			}
9503252Sdp			$page = "";
9513252Sdp			$doprint = 1;
9523252Sdp			next;
9530Sstevel@tonic-gate		}
9540Sstevel@tonic-gate
9553252Sdp		# Skip from %%Trailer of one document to Endprolog
9563252Sdp		# %%Page of the next
9573252Sdp		$doprint = 0 if (/^%%Trailer/);
9583252Sdp		$page .= $_ if ($doprint);
9590Sstevel@tonic-gate	}
9603252Sdp
9613252Sdp	if ($page =~ /\)S/) {
9623252Sdp		print "%%Page: ? $pno\n";
9633252Sdp		print $page;
9643252Sdp	} else {
9653252Sdp		$pno--;
9660Sstevel@tonic-gate	}
9673252Sdp	print "%%Trailer\n%%Pages: $pno\n";
9683252SdpEOF
9690Sstevel@tonic-gate
9703295Sdp	$PERL /tmp/$$.crmerge.pl < $infile
9710Sstevel@tonic-gate}
9723252Sdp
9730Sstevel@tonic-gate
9743252Sdp#
9753252Sdp# input_cmd | insert_anchors | output_cmd
9763252Sdp#
9770Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
9783252Sdp# anchors.  These are used to drive the frames version of the
9790Sstevel@tonic-gate# sdiffs output.
9800Sstevel@tonic-gate#
9810Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
9820Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
9830Sstevel@tonic-gate#
9843252Sdp# The script detects changed lines as any line that has a "<span
9853252Sdp# class=" string embedded (unchanged lines have no class set and are
9863252Sdp# not part of a <span>.  Blank lines (without a sequence number)
9870Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
9880Sstevel@tonic-gate# deleted.
9890Sstevel@tonic-gate#
9903252Sdpfunction insert_anchors
9913252Sdp{
9927078Smjnelson	$AWK '
9933252Sdp	function ia() {
9943252Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
9953252Sdp	}
9960Sstevel@tonic-gate
9973252Sdp	BEGIN {
9983252Sdp		anc=1;
9993252Sdp		inblock=1;
10003252Sdp		printf "<pre>\n";
10013252Sdp	}
10023252Sdp	NF == 0 || /^<span class=/ {
10033252Sdp		if (inblock == 0) {
10043252Sdp			ia();
10053252Sdp			inblock=1;
10063252Sdp		}
10073252Sdp		print;
10083252Sdp		next;
10093252Sdp	}
10103252Sdp	{
10113252Sdp		inblock=0;
10123252Sdp		print;
10133252Sdp	}
10143252Sdp	END {
10150Sstevel@tonic-gate		ia();
10163252Sdp
10173252Sdp		printf "<b style=\"font-size: large; color: red\">";
10183252Sdp		printf "--- EOF ---</b>"
101910789SEdward.Pilatowicz@Sun.COM		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
10203252Sdp		printf "</pre>"
10213252Sdp		printf "<form name=\"eof\">";
10226922Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
10236922Smjnelson		    "type=\"hidden\"></input>", anc - 1;
10243252Sdp		printf "</form>";
10250Sstevel@tonic-gate	}
10263252Sdp	' $1
10270Sstevel@tonic-gate}
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate
10303252Sdp#
10313252Sdp# relative_dir
10320Sstevel@tonic-gate#
10333252Sdp# Print a relative return path from $1 to $2.  For example if
10343252Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
10353252Sdp# this function would print "../../../../".
10363252Sdp#
10373252Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
10383252Sdp# and $2 is returned-- the result of this is that the resulting webrev
10393252Sdp# is not relocatable.
10400Sstevel@tonic-gate#
10413252Sdpfunction relative_dir
10423252Sdp{
10439191SMark.J.Nelson@Sun.COM        typeset cur="${1##$2?(/)}"
10449191SMark.J.Nelson@Sun.COM
10459191SMark.J.Nelson@Sun.COM        #
10469191SMark.J.Nelson@Sun.COM        # If the first path was specified absolutely, and it does
10479191SMark.J.Nelson@Sun.COM        # not start with the second path, it's an error.
10489191SMark.J.Nelson@Sun.COM        #
10499193SMark.J.Nelson@Sun.COM        if [[ "$cur" = "/${1#/}" ]]; then
10509191SMark.J.Nelson@Sun.COM                # Should never happen.
10519191SMark.J.Nelson@Sun.COM                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
10529191SMark.J.Nelson@Sun.COM                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
10539191SMark.J.Nelson@Sun.COM                print -u2 "will not be relocatable!"
10549191SMark.J.Nelson@Sun.COM                print $2
10559191SMark.J.Nelson@Sun.COM                return
10569191SMark.J.Nelson@Sun.COM        fi
10579191SMark.J.Nelson@Sun.COM
10589191SMark.J.Nelson@Sun.COM	#
10599191SMark.J.Nelson@Sun.COM	# This is kind of ugly.  The sed script will do the following:
10609191SMark.J.Nelson@Sun.COM	#
10619191SMark.J.Nelson@Sun.COM	# 1. Strip off a leading "." or "./": this is important to get
10629191SMark.J.Nelson@Sun.COM	#    the correct arcnav links for files in $WDIR.
106310789SEdward.Pilatowicz@Sun.COM	# 2. Strip off a trailing "/": this is not strictly necessary,
10649191SMark.J.Nelson@Sun.COM	#    but is kind of nice, since it doesn't end up in "//" at
10659191SMark.J.Nelson@Sun.COM	#    the end of a relative path.
10669191SMark.J.Nelson@Sun.COM	# 3. Replace all remaining sequences of non-"/" with "..": the
10679191SMark.J.Nelson@Sun.COM	#    assumption here is that each dirname represents another
10689191SMark.J.Nelson@Sun.COM	#    level of relative separation.
10699191SMark.J.Nelson@Sun.COM	# 4. Append a trailing "/" only for non-empty paths: this way
10709191SMark.J.Nelson@Sun.COM	#    the caller doesn't need to duplicate this logic, and does
10719191SMark.J.Nelson@Sun.COM	#    not end up using $RTOP/file for files in $WDIR.
10729191SMark.J.Nelson@Sun.COM	#
10739193SMark.J.Nelson@Sun.COM	print $cur | $SED -e '{
10749193SMark.J.Nelson@Sun.COM		s:^\./*::
10759193SMark.J.Nelson@Sun.COM		s:/$::
10769193SMark.J.Nelson@Sun.COM		s:[^/][^/]*:..:g
10779193SMark.J.Nelson@Sun.COM		s:^\(..*\)$:\1/:
10789193SMark.J.Nelson@Sun.COM	}'
10790Sstevel@tonic-gate}
10800Sstevel@tonic-gate
10813252Sdp#
10823252Sdp# frame_nav_js
10833252Sdp#
10843252Sdp# Emit javascript for frame navigation
10853252Sdp#
10863252Sdpfunction frame_nav_js
10870Sstevel@tonic-gate{
10880Sstevel@tonic-gatecat << \EOF
10890Sstevel@tonic-gatevar myInt;
10900Sstevel@tonic-gatevar scrolling=0;
10913252Sdpvar sfactor = 3;
10920Sstevel@tonic-gatevar scount=10;
10930Sstevel@tonic-gate
10940Sstevel@tonic-gatefunction scrollByPix() {
10950Sstevel@tonic-gate	if (scount<=0) {
10960Sstevel@tonic-gate		sfactor*=1.2;
10970Sstevel@tonic-gate		scount=10;
10980Sstevel@tonic-gate	}
10990Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11000Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11010Sstevel@tonic-gate	scount--;
11020Sstevel@tonic-gate}
11030Sstevel@tonic-gate
11043252Sdpfunction scrollToAnc(num) {
11053252Sdp
11063252Sdp	// Update the value of the anchor in the form which we use as
11073252Sdp	// storage for this value.  setAncValue() will take care of
11083252Sdp	// correcting for overflow and underflow of the value and return
11093252Sdp	// us the new value.
11103252Sdp	num = setAncValue(num);
11113252Sdp
11123252Sdp	// Set location and scroll back a little to expose previous
11133252Sdp	// lines.
11143252Sdp	//
11153252Sdp	// Note that this could be improved: it is possible although
11163252Sdp	// complex to compute the x and y position of an anchor, and to
11173252Sdp	// scroll to that location directly.
11183252Sdp	//
11190Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11200Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
11213252Sdp
11220Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11230Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11240Sstevel@tonic-gate}
11250Sstevel@tonic-gate
11263252Sdpfunction getAncValue()
11273252Sdp{
11283252Sdp	return (parseInt(parent.nav.document.diff.real.value));
11293252Sdp}
11303252Sdp
11313252Sdpfunction setAncValue(val)
11323252Sdp{
11333252Sdp	if (val <= 0) {
11343252Sdp		val = 0;
11353252Sdp		parent.nav.document.diff.real.value = val;
11363252Sdp		parent.nav.document.diff.display.value = "BOF";
11373252Sdp		return (val);
11383252Sdp	}
11393252Sdp
11403252Sdp	//
11413252Sdp	// The way we compute the max anchor value is to stash it
11423252Sdp	// inline in the left and right hand side pages-- it's the same
11433252Sdp	// on each side, so we pluck from the left.
11443252Sdp	//
11453252Sdp	maxval = parent.lhs.document.eof.value.value;
11463252Sdp	if (val < maxval) {
11473252Sdp		parent.nav.document.diff.real.value = val;
11483252Sdp		parent.nav.document.diff.display.value = val.toString();
11493252Sdp		return (val);
11503252Sdp	}
11513252Sdp
11523252Sdp	// this must be: val >= maxval
11533252Sdp	val = maxval;
11543252Sdp	parent.nav.document.diff.real.value = val;
11553252Sdp	parent.nav.document.diff.display.value = "EOF";
11563252Sdp	return (val);
11573252Sdp}
11583252Sdp
11590Sstevel@tonic-gatefunction stopScroll() {
11600Sstevel@tonic-gate	if (scrolling==1) {
11610Sstevel@tonic-gate		clearInterval(myInt);
11620Sstevel@tonic-gate		scrolling=0;
11630Sstevel@tonic-gate	}
11640Sstevel@tonic-gate}
11650Sstevel@tonic-gate
11660Sstevel@tonic-gatefunction startScroll() {
11670Sstevel@tonic-gate	stopScroll();
11680Sstevel@tonic-gate	scrolling=1;
11690Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
11700Sstevel@tonic-gate}
11710Sstevel@tonic-gate
11723252Sdpfunction handlePress(b) {
11733252Sdp
11740Sstevel@tonic-gate	switch (b) {
11750Sstevel@tonic-gate	    case 1 :
11763252Sdp		scrollToAnc(-1);
11770Sstevel@tonic-gate		break;
11780Sstevel@tonic-gate	    case 2 :
11793252Sdp		scrollToAnc(getAncValue() - 1);
11800Sstevel@tonic-gate		break;
11810Sstevel@tonic-gate	    case 3 :
11820Sstevel@tonic-gate		sfactor=-3;
11830Sstevel@tonic-gate		startScroll();
11840Sstevel@tonic-gate		break;
11850Sstevel@tonic-gate	    case 4 :
11860Sstevel@tonic-gate		sfactor=3;
11870Sstevel@tonic-gate		startScroll();
11880Sstevel@tonic-gate		break;
11890Sstevel@tonic-gate	    case 5 :
11903252Sdp		scrollToAnc(getAncValue() + 1);
11910Sstevel@tonic-gate		break;
11920Sstevel@tonic-gate	    case 6 :
11933252Sdp		scrollToAnc(999999);
11940Sstevel@tonic-gate		break;
11950Sstevel@tonic-gate	}
11960Sstevel@tonic-gate}
11970Sstevel@tonic-gate
11980Sstevel@tonic-gatefunction handleRelease(b) {
11990Sstevel@tonic-gate	stopScroll();
12000Sstevel@tonic-gate}
12010Sstevel@tonic-gate
12023252Sdpfunction keypress(ev) {
12033252Sdp	var keynum;
12043252Sdp	var keychar;
12053252Sdp
12063252Sdp	if (window.event) { // IE
12073252Sdp		keynum = ev.keyCode;
12083252Sdp	} else if (ev.which) { // non-IE
12093252Sdp		keynum = ev.which;
12100Sstevel@tonic-gate	}
12113252Sdp
12123252Sdp	keychar = String.fromCharCode(keynum);
12133252Sdp
12143252Sdp	if (keychar == "k") {
12153252Sdp		handlePress(2);
12163252Sdp		return (0);
12173252Sdp	} else if (keychar == "j" || keychar == " ") {
12183252Sdp		handlePress(5);
12193252Sdp		return (0);
12203252Sdp	}
12213252Sdp	return (1);
12220Sstevel@tonic-gate}
12230Sstevel@tonic-gate
12243252Sdpfunction ValidateDiffNum(){
12253252Sdp	val = parent.nav.document.diff.display.value;
12263252Sdp	if (val == "EOF") {
12273252Sdp		scrollToAnc(999999);
12283252Sdp		return;
12293252Sdp	}
12303252Sdp
12313252Sdp	if (val == "BOF") {
12323252Sdp		scrollToAnc(0);
12333252Sdp		return;
12343252Sdp	}
12353252Sdp
12363252Sdp        i=parseInt(val);
12373252Sdp        if (isNaN(i)) {
12383252Sdp                parent.nav.document.diff.display.value = getAncValue();
12393252Sdp        } else {
12403252Sdp                scrollToAnc(i);
12413252Sdp        }
12423252Sdp        return false;
12433252Sdp}
12443252Sdp
12453252SdpEOF
12463252Sdp}
12473252Sdp
12483252Sdp#
12493252Sdp# frame_navigation
12503252Sdp#
12513252Sdp# Output anchor navigation file for framed sdiffs.
12523252Sdp#
12533252Sdpfunction frame_navigation
12543252Sdp{
12553252Sdp	print "$HTML<head>$STDHEAD"
12563252Sdp
12573252Sdp	cat << \EOF
12583252Sdp<title>Anchor Navigation</title>
12593252Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
12603252Sdp<meta http-equiv="Content-Type" content="text/html">
12613252Sdp
12623252Sdp<style type="text/css">
12633252Sdp    div.button td { padding-left: 5px; padding-right: 5px;
12643252Sdp		    background-color: #eee; text-align: center;
12653252Sdp		    border: 1px #444 outset; cursor: pointer; }
12663252Sdp    div.button a { font-weight: bold; color: black }
12673252Sdp    div.button td:hover { background: #ffcc99; }
12683252Sdp</style>
12693252SdpEOF
12703252Sdp
12716922Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
12723252Sdp
12733252Sdp	cat << \EOF
12743252Sdp</head>
12753252Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
12763252Sdp	onkeypress="keypress(event);">
12770Sstevel@tonic-gate    <noscript lang="javascript">
12780Sstevel@tonic-gate      <center>
12796922Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
12800Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
12810Sstevel@tonic-gate      </center>
12820Sstevel@tonic-gate    </noscript>
12830Sstevel@tonic-gate    <table width="100%" border="0" align="center">
12843252Sdp	<tr>
12853252Sdp          <td valign="middle" width="25%">Diff navigation:
12863252Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
12873252Sdp          at right</td>
12883252Sdp	  <td align="center" valign="top" width="50%">
12890Sstevel@tonic-gate	    <div class="button">
12903252Sdp	      <table border="0" align="center">
12913252Sdp                  <tr>
12923252Sdp		    <td>
12930Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
12940Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
12950Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
12960Sstevel@tonic-gate			 onClick="return false;"
12970Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
12983252Sdp		    <td>
12990Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13000Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13010Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13020Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
13033252Sdp			 onClick="return false;">Scroll Up</a></td>
13043252Sdp		    <td>
13050Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13060Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13073252Sdp			 onMouseOut="handleRelease(2);return true;"
13080Sstevel@tonic-gate			 title="Go to previous Diff"
13090Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13100Sstevel@tonic-gate		    </td></tr>
13113252Sdp
13120Sstevel@tonic-gate		  <tr>
13133252Sdp		    <td>
13143252Sdp		      <a onMouseDown="handlePress(6);return true;"
13153252Sdp			 onMouseUp="handleRelease(6);return true;"
13163252Sdp			 onMouseOut="handleRelease(6);return true;"
13170Sstevel@tonic-gate			 onClick="return false;"
13180Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
13193252Sdp		    <td>
13203252Sdp		      <a onMouseDown="handlePress(4);return true;"
13213252Sdp			 onMouseUp="handleRelease(4);return true;"
13223252Sdp			 onMouseOut="handleRelease(4);return true;"
13230Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
13243252Sdp			 onClick="return false;">Scroll Down</a></td>
13253252Sdp		    <td>
13263252Sdp		      <a onMouseDown="handlePress(5);return true;"
13273252Sdp			 onMouseUp="handleRelease(5);return true;"
13283252Sdp			 onMouseOut="handleRelease(5);return true;"
13290Sstevel@tonic-gate			 title="Go to next Diff"
13300Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
13313252Sdp		  </tr>
13323252Sdp              </table>
13333252Sdp	    </div>
13343252Sdp	  </td>
13350Sstevel@tonic-gate	  <th valign="middle" width="25%">
13363252Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
13376922Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
13386922Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
13390Sstevel@tonic-gate	    </form>
13400Sstevel@tonic-gate	  </th>
13413252Sdp	</tr>
13420Sstevel@tonic-gate    </table>
13430Sstevel@tonic-gate  </body>
13440Sstevel@tonic-gate</html>
13450Sstevel@tonic-gateEOF
13460Sstevel@tonic-gate}
13470Sstevel@tonic-gate
13483252Sdp
13490Sstevel@tonic-gate
13503252Sdp#
13513252Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
13523252Sdp#
13533252Sdp# Processes the output of diff to produce an HTML file representing either
13543252Sdp# context or unified diffs.
13553252Sdp#
13560Sstevel@tonic-gatediff_to_html()
13570Sstevel@tonic-gate{
13583252Sdp	TNAME=$1
13593252Sdp	TPATH=$2
13603252Sdp	DIFFTYPE=$3
13613252Sdp	COMMENT=$4
13623252Sdp
13633252Sdp	print "$HTML<head>$STDHEAD"
13643252Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
13653252Sdp
13663252Sdp	if [[ $DIFFTYPE == "U" ]]; then
13673252Sdp		print "$UDIFFCSS"
13683252Sdp	fi
13693252Sdp
13703252Sdp	cat <<-EOF
13713252Sdp	</head>
13723252Sdp	<body id="SUNWwebrev">
13733252Sdp        <a class="print" href="javascript:print()">Print this page</a>
13743252Sdp	<pre>$COMMENT</pre>
13753252Sdp        <pre>
13763252Sdp	EOF
13770Sstevel@tonic-gate
13787078Smjnelson	html_quote | $AWK '
13793252Sdp	/^--- new/	{ next }
13803252Sdp	/^\+\+\+ new/	{ next }
13813252Sdp	/^--- old/	{ next }
13823252Sdp	/^\*\*\* old/	{ next }
13833252Sdp	/^\*\*\*\*/	{ next }
13843252Sdp	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
13856922Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
13863252Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
13873252Sdp			  next}
13883252Sdp
13896922Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
13903252Sdp			  next}
13913252Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
13923252Sdp			  next}
13933252Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
13943252Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
13953252Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
13963252Sdp			{printf "%s\n", $0; next}
13973252Sdp	'
13983252Sdp
13993252Sdp	print "</pre></body></html>\n"
14000Sstevel@tonic-gate}
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate
14033252Sdp#
14043252Sdp# source_to_html { new | old } <filename>
14053252Sdp#
14063252Sdp# Process a plain vanilla source file to transform it into an HTML file.
14073252Sdp#
14080Sstevel@tonic-gatesource_to_html()
14090Sstevel@tonic-gate{
14103252Sdp	WHICH=$1
14113252Sdp	TNAME=$2
14120Sstevel@tonic-gate
14133252Sdp	print "$HTML<head>$STDHEAD"
14147078Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
14153252Sdp	print "<body id=\"SUNWwebrev\">"
14163252Sdp	print "<pre>"
14177078Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
14183252Sdp	print "</pre></body></html>"
14190Sstevel@tonic-gate}
14200Sstevel@tonic-gate
14213252Sdp#
14227078Smjnelson# comments_from_teamware {text|html} parent-file child-file
14233252Sdp#
14243252Sdp# Find the first delta in the child that's not in the parent.  Get the
14253252Sdp# newest delta from the parent, get all deltas from the child starting
14263252Sdp# with that delta, and then get all info starting with the second oldest
14273252Sdp# delta in that list (the first delta unique to the child).
14280Sstevel@tonic-gate#
14290Sstevel@tonic-gate# This code adapted from Bill Shannon's "spc" script
14303252Sdp#
14313252Sdpcomments_from_teamware()
14320Sstevel@tonic-gate{
14333252Sdp	fmt=$1
14343252Sdp	pfile=$PWS/$2
14353252Sdp	cfile=$CWS/$3
14360Sstevel@tonic-gate
14377078Smjnelson	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
14387078Smjnelson		pfile=$RWS/$2
14397078Smjnelson	fi
14407078Smjnelson
14413252Sdp	if [[ -f $pfile ]]; then
14427078Smjnelson		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
14433252Sdp	else
14443252Sdp		psid=1.1
14453252Sdp	fi
14460Sstevel@tonic-gate
14477078Smjnelson	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
14483252Sdp	N=${#sids[@]}
14490Sstevel@tonic-gate
14503252Sdp	nawkprg='
14513252Sdp		/^COMMENTS:/	{p=1; continue}
14523252Sdp		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
14533252Sdp		NF == 0u	{ continue }
14543252Sdp		{if (p==0) continue; print $0 }'
14553252Sdp
14563252Sdp	if [[ $N -ge 2 ]]; then
14573252Sdp		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
14580Sstevel@tonic-gate
14593252Sdp		if [[ $fmt == "text" ]]; then
14607078Smjnelson			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
14617078Smjnelson			    $AWK "$nawkprg"
14623252Sdp			return
14633252Sdp		fi
14643252Sdp
14657078Smjnelson		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
14669193SMark.J.Nelson@Sun.COM		    html_quote | its2url | $AWK "$nawkprg"
14673252Sdp	fi
14680Sstevel@tonic-gate}
14690Sstevel@tonic-gate
14703252Sdp#
14717078Smjnelson# comments_from_wx {text|html} filepath
14723252Sdp#
14737078Smjnelson# Given the pathname of a file, find its location in a "wx" active
14747078Smjnelson# file list and print the following comment.  Output is either text or
14757078Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
14767078Smjnelson# are turned into URLs.
14777078Smjnelson#
14787078Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
14793252Sdp#
14803252Sdpcomments_from_wx()
14813252Sdp{
14823252Sdp	typeset fmt=$1
14833252Sdp	typeset p=$2
14840Sstevel@tonic-gate
14857078Smjnelson	comm=`$AWK '
14863252Sdp	$1 == "'$p'" {
14870Sstevel@tonic-gate		do getline ; while (NF > 0)
14880Sstevel@tonic-gate		getline
14890Sstevel@tonic-gate		while (NF > 0) { print ; getline }
14900Sstevel@tonic-gate		exit
14913252Sdp	}' < $wxfile`
14923252Sdp
14937078Smjnelson	if [[ -z $comm ]]; then
14947078Smjnelson		comm="*** NO COMMENTS ***"
14957078Smjnelson	fi
14967078Smjnelson
14973252Sdp	if [[ $fmt == "text" ]]; then
14987078Smjnelson		print -- "$comm"
14993252Sdp		return
15003252Sdp	fi
15013252Sdp
15029193SMark.J.Nelson@Sun.COM	print -- "$comm" | html_quote | its2url
15037078Smjnelson
15040Sstevel@tonic-gate}
15050Sstevel@tonic-gate
15063252Sdp#
15073252Sdp# getcomments {text|html} filepath parentpath
15083252Sdp#
15093252Sdp# Fetch the comments depending on what SCM mode we're in.
15103252Sdp#
15113252Sdpgetcomments()
15123252Sdp{
15133252Sdp	typeset fmt=$1
15143252Sdp	typeset p=$2
15153252Sdp	typeset pp=$3
15163252Sdp
15177310SDarren.Moffat@Sun.COM	if [[ -n $Nflag ]]; then
15187310SDarren.Moffat@Sun.COM		return
15197310SDarren.Moffat@Sun.COM	fi
15207078Smjnelson	#
15217078Smjnelson	# Mercurial support uses a file list in wx format, so this
15227078Smjnelson	# will be used there, too
15237078Smjnelson	#
15243252Sdp	if [[ -n $wxfile ]]; then
15253252Sdp		comments_from_wx $fmt $p
15263252Sdp	else
15273252Sdp		if [[ $SCM_MODE == "teamware" ]]; then
15283252Sdp			comments_from_teamware $fmt $pp $p
15293252Sdp		fi
15303252Sdp	fi
15313252Sdp}
15320Sstevel@tonic-gate
15333252Sdp#
15343252Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
15353252Sdp#
15363252Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
15373252Sdp#
15383252Sdpfunction printCI
15393252Sdp{
15403252Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
15413252Sdp	typeset str
15423252Sdp	if (( tot == 1 )); then
15433252Sdp		str="line"
15443252Sdp	else
15453252Sdp		str="lines"
15463252Sdp	fi
15473252Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
15483252Sdp	    $tot $str $ins $del $mod $unc
15493252Sdp}
15503252Sdp
15513252Sdp
15523252Sdp#
15533252Sdp# difflines <oldfile> <newfile>
15543252Sdp#
15553252Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
15563252Sdp# and total lines changed, the sum of added + removed + modified.
15573252Sdp#
15580Sstevel@tonic-gatefunction difflines
15590Sstevel@tonic-gate{
15603252Sdp	integer tot mod del ins unc err
15613252Sdp	typeset filename
15623252Sdp
15637078Smjnelson	eval $( diff -e $1 $2 | $AWK '
15643252Sdp	# Change range of lines: N,Nc
15653252Sdp	/^[0-9]*,[0-9]*c$/ {
15663252Sdp		n=split(substr($1,1,length($1)-1), counts, ",");
15673252Sdp		if (n != 2) {
15683252Sdp		    error=2
15693252Sdp		    exit;
15703252Sdp		}
15713252Sdp		#
15723252Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
15733252Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
15743252Sdp		#
15753252Sdp		r=(counts[2]-counts[1])+1;
15760Sstevel@tonic-gate
15773252Sdp		#
15783252Sdp		# Now count replacement lines: each represents a change instead
15793252Sdp		# of a delete, so increment c and decrement r.
15803252Sdp		#
15813252Sdp		while (getline != /^\.$/) {
15823252Sdp			c++;
15833252Sdp			r--;
15843252Sdp		}
15853252Sdp		#
15863252Sdp		# If there were more replacement lines than original lines,
15873252Sdp		# then r will be negative; in this case there are no deletions,
15883252Sdp		# but there are r changes that should be counted as adds, and
15893252Sdp		# since r is negative, subtract it from a and add it to c.
15903252Sdp		#
15913252Sdp		if (r < 0) {
15923252Sdp			a-=r;
15933252Sdp			c+=r;
15943252Sdp		}
15950Sstevel@tonic-gate
15963252Sdp		#
15973252Sdp		# If there were more original lines than replacement lines, then
15983252Sdp		# r will be positive; in this case, increment d by that much.
15993252Sdp		#
16003252Sdp		if (r > 0) {
16013252Sdp			d+=r;
16023252Sdp		}
16033252Sdp		next;
16040Sstevel@tonic-gate	}
16050Sstevel@tonic-gate
16063252Sdp	# Change lines: Nc
16073252Sdp	/^[0-9].*c$/ {
16083252Sdp		# The first line is a replacement; any more are additions.
16093252Sdp		if (getline != /^\.$/) {
16103252Sdp			c++;
16113252Sdp			while (getline != /^\.$/) a++;
16123252Sdp		}
16133252Sdp		next;
16143252Sdp	}
16150Sstevel@tonic-gate
16163252Sdp	# Add lines: both Na and N,Na
16173252Sdp	/^[0-9].*a$/ {
16183252Sdp		while (getline != /^\.$/) a++;
16193252Sdp		next;
16200Sstevel@tonic-gate	}
16210Sstevel@tonic-gate
16223252Sdp	# Delete range of lines: N,Nd
16233252Sdp	/^[0-9]*,[0-9]*d$/ {
16243252Sdp		n=split(substr($1,1,length($1)-1), counts, ",");
16253252Sdp		if (n != 2) {
16263252Sdp			error=2
16273252Sdp			exit;
16283252Sdp		}
16293252Sdp		#
16303252Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
16313252Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
16323252Sdp		#
16333252Sdp		r=(counts[2]-counts[1])+1;
16343252Sdp		d+=r;
16353252Sdp		next;
16363252Sdp	}
16373252Sdp
16383252Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16393252Sdp	/^[0-9]*d$/ {d++; next}
16400Sstevel@tonic-gate
16413252Sdp	# Should not get here!
16423252Sdp	{
16433252Sdp		error=1;
16443252Sdp		exit;
16453252Sdp	}
16460Sstevel@tonic-gate
16473252Sdp	# Finish off - print results
16483252Sdp	END {
16493252Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16503252Sdp		    (c+d+a), c, d, a, error);
16513252Sdp	}' )
16520Sstevel@tonic-gate
16537078Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16543252Sdp	if (( $? > 0 || err > 0 )); then
16553252Sdp		print "Unexpected Error occurred reading" \
16563252Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
16573252Sdp		return
16583252Sdp	fi
16593252Sdp
16600Sstevel@tonic-gate	# Accumulate totals
16610Sstevel@tonic-gate	(( TOTL += tot ))
16623252Sdp	(( TMOD += mod ))
16633252Sdp	(( TDEL += del ))
16640Sstevel@tonic-gate	(( TINS += ins ))
16650Sstevel@tonic-gate	# Calculate unchanged lines
16667078Smjnelson	unc=`wc -l < $1`
16670Sstevel@tonic-gate	if (( unc > 0 )); then
16683252Sdp		(( unc -= del + mod ))
16693252Sdp		(( TUNC += unc ))
16700Sstevel@tonic-gate	fi
16710Sstevel@tonic-gate	# print summary
16723252Sdp	print "<span class=\"lineschanged\">"
16733252Sdp	printCI $tot $ins $del $mod $unc
16743252Sdp	print "</span>"
16753252Sdp}
16763252Sdp
16773252Sdp
16783252Sdp#
16793252Sdp# flist_from_wx
16803252Sdp#
16813252Sdp# Sets up webrev to source its information from a wx-formatted file.
16823252Sdp# Sets the global 'wxfile' variable.
16833252Sdp#
16843252Sdpfunction flist_from_wx
16853252Sdp{
16863252Sdp	typeset argfile=$1
16873252Sdp	if [[ -n ${argfile%%/*} ]]; then
16883252Sdp		#
16893252Sdp		# If the wx file pathname is relative then make it absolute
16903252Sdp		# because the webrev does a "cd" later on.
16913252Sdp		#
16923252Sdp		wxfile=$PWD/$argfile
16933252Sdp	else
16943252Sdp		wxfile=$argfile
16953252Sdp	fi
16963252Sdp
16977078Smjnelson	$AWK '{ c = 1; print;
16983252Sdp	  while (getline) {
16993252Sdp		if (NF == 0) { c = -c; continue }
17003252Sdp		if (c > 0) print
17013252Sdp	  }
17023252Sdp	}' $wxfile > $FLIST
17033252Sdp
17043252Sdp	print " Done."
17053252Sdp}
17063252Sdp
17073252Sdp#
17083252Sdp# flist_from_teamware [ <args-to-putback-n> ]
17093252Sdp#
17103252Sdp# Generate the file list by extracting file names from a putback -n.  Some
17113252Sdp# names may come from the "update/create" messages and others from the
17123252Sdp# "currently checked out" warning.  Renames are detected here too.  Extract
17133252Sdp# values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
17143252Sdp# -n as well, but remove them if they are already defined.
17153252Sdp#
17163252Sdpfunction flist_from_teamware
17173252Sdp{
17187078Smjnelson	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
17193252Sdp		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
17203252Sdp			print -u2 "parent $codemgr_parent doesn't look like a" \
17213252Sdp			    "valid teamware workspace"
17223252Sdp			exit 1
17233252Sdp		fi
17243252Sdp		parent_args="-p $codemgr_parent"
17253252Sdp	fi
17263252Sdp
17273252Sdp	print " File list from: 'putback -n $parent_args $*' ... \c"
17283252Sdp
17293252Sdp	putback -n $parent_args $* 2>&1 |
17307078Smjnelson	    $AWK '
17313252Sdp		/^update:|^create:/	{print $2}
17323252Sdp		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
17333252Sdp		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
17343252Sdp		/^The following files are currently checked out/ {p = 1; continue}
17353252Sdp		NF == 0			{p=0 ; continue}
17363252Sdp		/^rename/		{old=$3}
17373252Sdp		$1 == "to:"		{print $2, old}
17383252Sdp		/^"/			{continue}
17393252Sdp		p == 1			{print $1}' |
17403252Sdp	    sort -r -k 1,1 -u | sort > $FLIST
17413252Sdp
17423252Sdp	print " Done."
17430Sstevel@tonic-gate}
17440Sstevel@tonic-gate
17457078Smjnelson#
17467078Smjnelson# Call hg-active to get the active list output in the wx active list format
17477078Smjnelson#
17487078Smjnelsonfunction hg_active_wxfile
17497078Smjnelson{
17507078Smjnelson	typeset child=$1
17517078Smjnelson	typeset parent=$2
17527078Smjnelson
17537078Smjnelson	TMPFLIST=/tmp/$$.active
17547298SMark.J.Nelson@Sun.COM	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
17557078Smjnelson	wxfile=$TMPFLIST
17567078Smjnelson}
17577078Smjnelson
17587078Smjnelson#
17597078Smjnelson# flist_from_mercurial
17607078Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
17617078Smjnelson# flist_from_wx
17627078Smjnelson#
176310789SEdward.Pilatowicz@Sun.COMfunction flist_from_mercurial
17647078Smjnelson{
17657078Smjnelson	typeset child=$1
17667078Smjnelson	typeset parent=$2
17677078Smjnelson
17687078Smjnelson	print " File list from: hg-active -p $parent ...\c"
17697078Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
17707078Smjnelson		print		# Blank line for the \c above
17717078Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
17727078Smjnelson		exit 1
17737078Smjnelson	fi
17747078Smjnelson	hg_active_wxfile $child $parent
177510789SEdward.Pilatowicz@Sun.COM
17767078Smjnelson	# flist_from_wx prints the Done, so we don't have to.
17777078Smjnelson	flist_from_wx $TMPFLIST
17787078Smjnelson}
17797078Smjnelson
17807078Smjnelson#
17817078Smjnelson# flist_from_subversion
17827078Smjnelson#
17837078Smjnelson# Generate the file list by extracting file names from svn status.
17847078Smjnelson#
17857078Smjnelsonfunction flist_from_subversion
17867078Smjnelson{
17877078Smjnelson	CWS=$1
17887078Smjnelson	OLDPWD=$2
17897078Smjnelson
17907078Smjnelson	cd $CWS
17917078Smjnelson	print -u2 " File list from: svn status ... \c"
17927078Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
17937078Smjnelson	print -u2 " Done."
17947078Smjnelson	cd $OLDPWD
17957078Smjnelson}
17967078Smjnelson
17973252Sdpfunction env_from_flist
17980Sstevel@tonic-gate{
17993252Sdp	[[ -r $FLIST ]] || return
18003252Sdp
18013252Sdp	#
18023252Sdp	# Use "eval" to set env variables that are listed in the file
18033252Sdp	# list.  Then copy those into our local versions of those
18043252Sdp	# variables if they have not been set already.
18053252Sdp	#
18069079SVladimir.Kotal@Sun.COM	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18073252Sdp
18087078Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
18097078Smjnelson		codemgr_ws=$CODEMGR_WS
18107078Smjnelson		export CODEMGR_WS
18117078Smjnelson	fi
18123252Sdp
18133252Sdp	#
18143252Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
18153252Sdp	#
18167078Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
18177078Smjnelson		codemgr_parent=$CODEMGR_PARENT
18187078Smjnelson		export CODEMGR_PARENT
18193252Sdp	fi
18203252Sdp}
18213252Sdp
18223295Sdpfunction look_for_prog
18233295Sdp{
18243295Sdp	typeset path
18253295Sdp	typeset ppath
18263295Sdp	typeset progname=$1
18273295Sdp
18283295Sdp	ppath=$PATH
18293295Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
18303295Sdp	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
18317078Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
18323295Sdp
18333295Sdp	PATH=$ppath prog=`whence $progname`
18343295Sdp	if [[ -n $prog ]]; then
18353295Sdp		print $prog
18363295Sdp	fi
18373295Sdp}
18383295Sdp
18397078Smjnelsonfunction get_file_mode
18407078Smjnelson{
18417078Smjnelson	$PERL -e '
18427078Smjnelson		if (@stat = stat($ARGV[0])) {
18437078Smjnelson			$mode = $stat[2] & 0777;
18447078Smjnelson			printf "%03o\n", $mode;
18457078Smjnelson			exit 0;
18467078Smjnelson		} else {
18477078Smjnelson			exit 1;
18487078Smjnelson		}
18497078Smjnelson	    ' $1
18507078Smjnelson}
18517078Smjnelson
18527078Smjnelsonfunction build_old_new_teamware
18537078Smjnelson{
18547078Smjnelson	typeset olddir="$1"
18557078Smjnelson	typeset newdir="$2"
18567078Smjnelson
18577078Smjnelson	# If the child's version doesn't exist then
18587078Smjnelson	# get a readonly copy.
18597078Smjnelson
18607078Smjnelson	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
18617078Smjnelson		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
18627078Smjnelson	fi
18637078Smjnelson
18647078Smjnelson	# The following two sections propagate file permissions the
18657078Smjnelson	# same way SCCS does.  If the file is already under version
18667078Smjnelson	# control, always use permissions from the SCCS/s.file.  If
18677078Smjnelson	# the file is not under SCCS control, use permissions from the
18687078Smjnelson	# working copy.  In all cases, the file copied to the webrev
18697078Smjnelson	# is set to read only, and group/other permissions are set to
18707078Smjnelson	# match those of the file owner.  This way, even if the file
18717078Smjnelson	# is currently checked out, the webrev will display the final
18727078Smjnelson	# permissions that would result after check in.
18737078Smjnelson
18747078Smjnelson	#
18757078Smjnelson	# Snag new version of file.
18767078Smjnelson	#
18777078Smjnelson	rm -f $newdir/$DIR/$F
18787078Smjnelson	cp $CWS/$DIR/$F $newdir/$DIR/$F
18797078Smjnelson	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
18807078Smjnelson		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
18817078Smjnelson		    $newdir/$DIR/$F
18827078Smjnelson	fi
18837078Smjnelson	chmod u-w,go=u $newdir/$DIR/$F
18847078Smjnelson
18857078Smjnelson	#
18867078Smjnelson	# Get the parent's version of the file. First see whether the
18877078Smjnelson	# child's version is checked out and get the parent's version
18887078Smjnelson	# with keywords expanded or unexpanded as appropriate.
18897078Smjnelson	#
18907078Smjnelson	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
18917078Smjnelson	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
18927078Smjnelson		# Parent is not a real workspace, but just a raw
18937078Smjnelson		# directory tree - use the file that's there as
18947078Smjnelson		# the old file.
18957078Smjnelson
18967078Smjnelson		rm -f $olddir/$PDIR/$PF
18977078Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
18987078Smjnelson	else
18997078Smjnelson		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
19007078Smjnelson			real_parent=$PWS
19017078Smjnelson		else
19027078Smjnelson			real_parent=$RWS
19037078Smjnelson		fi
19047078Smjnelson
19057078Smjnelson		rm -f $olddir/$PDIR/$PF
19067078Smjnelson
19077078Smjnelson		if [[ -f $real_parent/$PDIR/$PF ]]; then
19087078Smjnelson			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
19097078Smjnelson				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
19107078Smjnelson				    $olddir/$PDIR/$PF
19117078Smjnelson			else
19127078Smjnelson				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
19137078Smjnelson				    $olddir/$PDIR/$PF
19147078Smjnelson			fi
19157078Smjnelson			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
19167078Smjnelson			    $olddir/$PDIR/$PF
19177078Smjnelson		fi
19187078Smjnelson	fi
19197078Smjnelson	if [[ -f $olddir/$PDIR/$PF ]]; then
19207078Smjnelson		chmod u-w,go=u $olddir/$PDIR/$PF
19217078Smjnelson	fi
19227078Smjnelson}
19237078Smjnelson
19247078Smjnelsonfunction build_old_new_mercurial
19257078Smjnelson{
19267078Smjnelson	typeset olddir="$1"
19277078Smjnelson	typeset newdir="$2"
19287078Smjnelson	typeset old_mode=
19297078Smjnelson	typeset new_mode=
19307078Smjnelson	typeset file
19317078Smjnelson
19327078Smjnelson	#
19337078Smjnelson	# Get old file mode, from the parent revision manifest entry.
19347078Smjnelson	# Mercurial only stores a "file is executable" flag, but the
19357078Smjnelson	# manifest will display an octal mode "644" or "755".
19367078Smjnelson	#
19377078Smjnelson	if [[ "$PDIR" == "." ]]; then
19387078Smjnelson		file="$PF"
19397078Smjnelson	else
19407078Smjnelson		file="$PDIR/$PF"
19417078Smjnelson	fi
19429079SVladimir.Kotal@Sun.COM	file=`echo $file | $SED 's#/#\\\/#g'`
19437078Smjnelson	# match the exact filename, and return only the permission digits
19449079SVladimir.Kotal@Sun.COM	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
19457078Smjnelson	    < $HG_PARENT_MANIFEST`
19467078Smjnelson
19477078Smjnelson	#
19487078Smjnelson	# Get new file mode, directly from the filesystem.
19497078Smjnelson	# Normalize the mode to match Mercurial's behavior.
19507078Smjnelson	#
19517078Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
19527078Smjnelson	if [[ -n "$new_mode" ]]; then
19537078Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
19547078Smjnelson			new_mode=755
19557078Smjnelson		else
19567078Smjnelson			new_mode=644
19577078Smjnelson		fi
19587078Smjnelson	fi
19597078Smjnelson
19607078Smjnelson	#
19617078Smjnelson	# new version of the file.
19627078Smjnelson	#
19637078Smjnelson	rm -rf $newdir/$DIR/$F
19647078Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
19657078Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
19667078Smjnelson		if [[ -n $new_mode ]]; then
19677078Smjnelson			chmod $new_mode $newdir/$DIR/$F
19687078Smjnelson		else
19697078Smjnelson			# should never happen
19707078Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
19717078Smjnelson		fi
19727078Smjnelson	fi
19737078Smjnelson
19747078Smjnelson	#
19757078Smjnelson	# parent's version of the file
19767078Smjnelson	#
19777078Smjnelson	# Note that we get this from the last version common to both
19787078Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
19797078Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
19807078Smjnelson	#
19817078Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
19827078Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
19837078Smjnelson	elif [[ -n $HG_PARENT ]]; then
19847078Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
19857078Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
19867078Smjnelson
19878018SVladimir.Kotal@Sun.COM		if (( $? != 0 )); then
19887078Smjnelson			rm -f $olddir/$PDIR/$PF
19897078Smjnelson		else
19907078Smjnelson			if [[ -n $old_mode ]]; then
19917078Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
19927078Smjnelson			else
19937078Smjnelson				# should never happen
19947078Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
19957078Smjnelson			fi
19967078Smjnelson		fi
19977078Smjnelson	fi
19987078Smjnelson}
19997078Smjnelson
20007078Smjnelsonfunction build_old_new_subversion
20017078Smjnelson{
20027078Smjnelson	typeset olddir="$1"
20037078Smjnelson	typeset newdir="$2"
20047078Smjnelson
20057078Smjnelson	# Snag new version of file.
20067078Smjnelson	rm -f $newdir/$DIR/$F
20077078Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
20087078Smjnelson
20097078Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
20107078Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
20117078Smjnelson	else
20127078Smjnelson		# Get the parent's version of the file.
20137078Smjnelson		svn status $CWS/$DIR/$F | read stat file
20147078Smjnelson		if [[ $stat != "A" ]]; then
20157078Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
20167078Smjnelson		fi
20177078Smjnelson	fi
20187078Smjnelson}
20197078Smjnelson
20207078Smjnelsonfunction build_old_new_unknown
20217078Smjnelson{
20227078Smjnelson	typeset olddir="$1"
20237078Smjnelson	typeset newdir="$2"
20247078Smjnelson
20257078Smjnelson	#
20267078Smjnelson	# Snag new version of file.
20277078Smjnelson	#
20287078Smjnelson	rm -f $newdir/$DIR/$F
20297078Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
20307078Smjnelson
20317078Smjnelson	#
20327078Smjnelson	# Snag the parent's version of the file.
203310789SEdward.Pilatowicz@Sun.COM	#
20347078Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
20357078Smjnelson		rm -f $olddir/$PDIR/$PF
20367078Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
20377078Smjnelson	fi
20387078Smjnelson}
20397078Smjnelson
20407078Smjnelsonfunction build_old_new
20417078Smjnelson{
20427078Smjnelson	typeset WDIR=$1
20437078Smjnelson	typeset PWS=$2
20447078Smjnelson	typeset PDIR=$3
20457078Smjnelson	typeset PF=$4
20467078Smjnelson	typeset CWS=$5
20477078Smjnelson	typeset DIR=$6
20487078Smjnelson	typeset F=$7
20497078Smjnelson
20507078Smjnelson	typeset olddir="$WDIR/raw_files/old"
20517078Smjnelson	typeset newdir="$WDIR/raw_files/new"
20527078Smjnelson
20537078Smjnelson	mkdir -p $olddir/$PDIR
20547078Smjnelson	mkdir -p $newdir/$DIR
20557078Smjnelson
20567078Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
20577078Smjnelson		build_old_new_teamware "$olddir" "$newdir"
20587078Smjnelson	elif [[ $SCM_MODE == "mercurial" ]]; then
20597078Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
20607078Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
20617078Smjnelson		build_old_new_subversion "$olddir" "$newdir"
20627078Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
20637078Smjnelson		build_old_new_unknown "$olddir" "$newdir"
20647078Smjnelson	fi
20657078Smjnelson
20667078Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
20677078Smjnelson		print "*** Error: file not in parent or child"
20687078Smjnelson		return 1
20697078Smjnelson	fi
20707078Smjnelson	return 0
20717078Smjnelson}
20727078Smjnelson
20737078Smjnelson
20743252Sdp#
20753252Sdp# Usage message.
20760Sstevel@tonic-gate#
20773252Sdpfunction usage
20783252Sdp{
20793252Sdp	print 'Usage:\twebrev [common-options]
20803252Sdp	webrev [common-options] ( <file> | - )
20813252Sdp	webrev [common-options] -w <wx file>
20823252Sdp
20833252SdpOptions:
20849193SMark.J.Nelson@Sun.COM	-C <filename>: Use <filename> for the information tracking configuration.
20858365SVladimir.Kotal@Sun.COM	-D: delete remote webrev
20868365SVladimir.Kotal@Sun.COM	-i <filename>: Include <filename> in the index.html file.
20879193SMark.J.Nelson@Sun.COM	-I <filename>: Use <filename> for the information tracking registry.
20888365SVladimir.Kotal@Sun.COM	-n: do not generate the webrev (useful with -U)
20893252Sdp	-O: Print bugids/arc cases suitable for OpenSolaris.
20903252Sdp	-o <outdir>: Output webrev to specified directory.
20913252Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
20928018SVladimir.Kotal@Sun.COM	-t <remote_target>: Specify remote destination for webrev upload
20938018SVladimir.Kotal@Sun.COM	-U: upload the webrev to remote destination
20943252Sdp	-w <wxfile>: Use specified wx active file.
20953252Sdp
20963252SdpEnvironment:
20973252Sdp	WDIR: Control the output directory.
20988365SVladimir.Kotal@Sun.COM	WEBREV_TRASH_DIR: Set directory for webrev delete.
20993252Sdp
21007078SmjnelsonSCM Specific Options:
21017078Smjnelson	TeamWare: webrev [common-options] -l [arguments to 'putback']
21027078Smjnelson
21033252SdpSCM Environment:
21047078Smjnelson	CODEMGR_WS: Workspace location.
21057078Smjnelson	CODEMGR_PARENT: Parent workspace location.
21063252Sdp'
21073252Sdp
21083252Sdp	exit 2
21093252Sdp}
21103252Sdp
21110Sstevel@tonic-gate#
21123252Sdp#
21133252Sdp# Main program starts here
21143252Sdp#
21153252Sdp#
21160Sstevel@tonic-gate
21170Sstevel@tonic-gatetrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
21180Sstevel@tonic-gate
21190Sstevel@tonic-gateset +o noclobber
21200Sstevel@tonic-gate
21217078SmjnelsonPATH=$(dirname $(whence $0)):$PATH
21227078Smjnelson
21233295Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
21243295Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
21257078Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
21267078Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
21273295Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
21283295Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
21293295Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
21308018SVladimir.Kotal@Sun.COM[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
21317078Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
21327078Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
21337078Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
21347078Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
21358018SVladimir.Kotal@Sun.COM[[ -z $SCP ]] && SCP=`look_for_prog scp`
21369079SVladimir.Kotal@Sun.COM[[ -z $SED ]] && SED=`look_for_prog sed`
21378018SVladimir.Kotal@Sun.COM[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
213810789SEdward.Pilatowicz@Sun.COM[[ -z $SORT ]] && SORT=`look_for_prog sort`
21398018SVladimir.Kotal@Sun.COM[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
21408018SVladimir.Kotal@Sun.COM[[ -z $GREP ]] && GREP=`look_for_prog grep`
21418365SVladimir.Kotal@Sun.COM[[ -z $FIND ]] && FIND=`look_for_prog find`
21428365SVladimir.Kotal@Sun.COM
21438365SVladimir.Kotal@Sun.COM# set name of trash directory for remote webrev deletion
21448365SVladimir.Kotal@Sun.COMTRASH_DIR=".trash"
21458365SVladimir.Kotal@Sun.COM[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
21463295Sdp
21473295Sdpif [[ ! -x $PERL ]]; then
21483295Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
21493295Sdp	exit 1
21500Sstevel@tonic-gatefi
21510Sstevel@tonic-gate
21527078Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
21537078Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
21547078Smjnelson	exit 1
21557078Smjnelsonfi
21567078Smjnelson
21573295Sdp#
21583295Sdp# These aren't fatal, but we want to note them to the user.
21593295Sdp# We don't warn on the absence of 'wx' until later when we've
21603295Sdp# determined that we actually need to try to invoke it.
21613295Sdp#
21623295Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
21633295Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
21643295Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
21653295Sdp
21663252Sdp# Declare global total counters.
21673252Sdpinteger TOTL TINS TDEL TMOD TUNC
21680Sstevel@tonic-gate
21698365SVladimir.Kotal@Sun.COM# default remote host for upload/delete
21708365SVladimir.Kotal@Sun.COMtypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
21719079SVladimir.Kotal@Sun.COM# prefixes for upload targets
21729079SVladimir.Kotal@Sun.COMtypeset -r rsync_prefix="rsync://"
21739079SVladimir.Kotal@Sun.COMtypeset -r ssh_prefix="ssh://"
21748365SVladimir.Kotal@Sun.COM
21759193SMark.J.Nelson@Sun.COMCflag=
21768365SVladimir.Kotal@Sun.COMDflag=
21773295Sdpflist_mode=
21783295Sdpflist_file=
21793252Sdpiflag=
21809193SMark.J.Nelson@Sun.COMIflag=
21818018SVladimir.Kotal@Sun.COMlflag=
21828018SVladimir.Kotal@Sun.COMNflag=
21838018SVladimir.Kotal@Sun.COMnflag=
21848018SVladimir.Kotal@Sun.COMOflag=
21853252Sdpoflag=
21863252Sdppflag=
21878018SVladimir.Kotal@Sun.COMtflag=
21888018SVladimir.Kotal@Sun.COMuflag=
21898018SVladimir.Kotal@Sun.COMUflag=
21903252Sdpwflag=
21918018SVladimir.Kotal@Sun.COMremote_target=
21928365SVladimir.Kotal@Sun.COM
21938365SVladimir.Kotal@Sun.COM#
21948365SVladimir.Kotal@Sun.COM# NOTE: when adding/removing options it is necessary to sync the list
219510789SEdward.Pilatowicz@Sun.COM#	with usr/src/tools/onbld/hgext/cdm.py
21968365SVladimir.Kotal@Sun.COM#
21979561SVladimir.Kotal@Sun.COMwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
21983252Sdpdo
21993252Sdp	case $opt in
22009193SMark.J.Nelson@Sun.COM	C)	Cflag=1
22019193SMark.J.Nelson@Sun.COM		ITSCONF=$OPTARG;;
22029193SMark.J.Nelson@Sun.COM
22038365SVladimir.Kotal@Sun.COM	D)	Dflag=1;;
22048365SVladimir.Kotal@Sun.COM
22053252Sdp	i)	iflag=1
22063252Sdp		INCLUDE_FILE=$OPTARG;;
22073252Sdp
22089193SMark.J.Nelson@Sun.COM	I)	Iflag=1
22099193SMark.J.Nelson@Sun.COM		ITSREG=$OPTARG;;
22109193SMark.J.Nelson@Sun.COM
22113252Sdp	#
22123252Sdp	# If -l has been specified, we need to abort further options
22133252Sdp	# processing, because subsequent arguments are going to be
22143252Sdp	# arguments to 'putback -n'.
22153252Sdp	#
22163252Sdp	l)	lflag=1
22173252Sdp		break;;
22180Sstevel@tonic-gate
22198018SVladimir.Kotal@Sun.COM	N)	Nflag=1;;
22208018SVladimir.Kotal@Sun.COM
22218018SVladimir.Kotal@Sun.COM	n)	nflag=1;;
22223252Sdp
22233252Sdp	O)	Oflag=1;;
22240Sstevel@tonic-gate
22258018SVladimir.Kotal@Sun.COM	o)	oflag=1
222611735SVladimir.Kotal@Sun.COM		# Strip the trailing slash to correctly form remote target.
222711735SVladimir.Kotal@Sun.COM		WDIR=${OPTARG%/};;
22288018SVladimir.Kotal@Sun.COM
22298018SVladimir.Kotal@Sun.COM	p)	pflag=1
22308018SVladimir.Kotal@Sun.COM		codemgr_parent=$OPTARG;;
22318018SVladimir.Kotal@Sun.COM
22328018SVladimir.Kotal@Sun.COM	t)	tflag=1
22338018SVladimir.Kotal@Sun.COM		remote_target=$OPTARG;;
22348018SVladimir.Kotal@Sun.COM
22358018SVladimir.Kotal@Sun.COM	U)	Uflag=1;;
22368018SVladimir.Kotal@Sun.COM
22378018SVladimir.Kotal@Sun.COM	w)	wflag=1;;
22387310SDarren.Moffat@Sun.COM
22393252Sdp	?)	usage;;
22403252Sdp	esac
22413252Sdpdone
22423252Sdp
22433252SdpFLIST=/tmp/$$.flist
22443252Sdp
22453252Sdpif [[ -n $wflag && -n $lflag ]]; then
22463252Sdp	usage
22470Sstevel@tonic-gatefi
22480Sstevel@tonic-gate
22498018SVladimir.Kotal@Sun.COM# more sanity checking
22508018SVladimir.Kotal@Sun.COMif [[ -n $nflag && -z $Uflag ]]; then
22518365SVladimir.Kotal@Sun.COM	print "it does not make sense to skip webrev generation" \
22528365SVladimir.Kotal@Sun.COM	    "without -U"
22538018SVladimir.Kotal@Sun.COM	exit 1
22548018SVladimir.Kotal@Sun.COMfi
22558018SVladimir.Kotal@Sun.COM
22568365SVladimir.Kotal@Sun.COMif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
22578365SVladimir.Kotal@Sun.COM	echo "remote target has to be used only for upload or delete"
22588018SVladimir.Kotal@Sun.COM	exit 1
22598018SVladimir.Kotal@Sun.COMfi
22608018SVladimir.Kotal@Sun.COM
22613252Sdp#
22629420SMark.J.Nelson@Sun.COM# For the invocation "webrev -n -U" with no other options, webrev will assume
22639420SMark.J.Nelson@Sun.COM# that the webrev exists in ${CWS}/webrev, but will upload it using the name
22649420SMark.J.Nelson@Sun.COM# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
22659420SMark.J.Nelson@Sun.COM# logic.
22669420SMark.J.Nelson@Sun.COM#
22679420SMark.J.Nelson@Sun.COM$WHICH_SCM | read SCM_MODE junk || exit 1
22689420SMark.J.Nelson@Sun.COMif [[ $SCM_MODE == "teamware" ]]; then
22699420SMark.J.Nelson@Sun.COM	#
22709420SMark.J.Nelson@Sun.COM	# Teamware priorities:
22719420SMark.J.Nelson@Sun.COM	# 1. CODEMGR_WS from the environment
22729420SMark.J.Nelson@Sun.COM	# 2. workspace name
22739420SMark.J.Nelson@Sun.COM	#
22749420SMark.J.Nelson@Sun.COM	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
22759420SMark.J.Nelson@Sun.COM	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
22769420SMark.J.Nelson@Sun.COM		print -u2 "$codemgr_ws: no such workspace"
22779420SMark.J.Nelson@Sun.COM		exit 1
22789420SMark.J.Nelson@Sun.COM	fi
22799420SMark.J.Nelson@Sun.COM	[[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
22809420SMark.J.Nelson@Sun.COM	codemgr_ws=$(cd $codemgr_ws;print $PWD)
22819420SMark.J.Nelson@Sun.COM	CODEMGR_WS=$codemgr_ws
22829420SMark.J.Nelson@Sun.COM	CWS=$codemgr_ws
22839420SMark.J.Nelson@Sun.COMelif [[ $SCM_MODE == "mercurial" ]]; then
22849420SMark.J.Nelson@Sun.COM	#
22859420SMark.J.Nelson@Sun.COM	# Mercurial priorities:
22869420SMark.J.Nelson@Sun.COM	# 1. hg root from CODEMGR_WS environment variable
2287*12776SJames.McPherson@Sun.COM	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
2288*12776SJames.McPherson@Sun.COM	#    usr/closed when we run webrev
22899420SMark.J.Nelson@Sun.COM	# 2. hg root from directory of invocation
22909420SMark.J.Nelson@Sun.COM	#
2291*12776SJames.McPherson@Sun.COM	if [[ ${PWD} =~ "usr/closed" ]]; then
2292*12776SJames.McPherson@Sun.COM		testparent=${CODEMGR_WS}/usr/closed
2293*12776SJames.McPherson@Sun.COM		# If we're in OpenSolaris mode, we enforce a minor policy:
2294*12776SJames.McPherson@Sun.COM		# help to make sure the reviewer doesn't accidentally publish
2295*12776SJames.McPherson@Sun.COM		# source which is under usr/closed
2296*12776SJames.McPherson@Sun.COM		if [[ -n "$Oflag" ]]; then
2297*12776SJames.McPherson@Sun.COM			print -u2 "OpenSolaris output not permitted with" \
2298*12776SJames.McPherson@Sun.COM			    "usr/closed changes"
2299*12776SJames.McPherson@Sun.COM			exit 1
2300*12776SJames.McPherson@Sun.COM		fi
2301*12776SJames.McPherson@Sun.COM	else
2302*12776SJames.McPherson@Sun.COM	        testparent=${CODEMGR_WS}
2303*12776SJames.McPherson@Sun.COM	fi
2304*12776SJames.McPherson@Sun.COM	[[ -z $codemgr_ws && -n $testparent ]] && \
2305*12776SJames.McPherson@Sun.COM	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
23069420SMark.J.Nelson@Sun.COM	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
23079420SMark.J.Nelson@Sun.COM	CWS=$codemgr_ws
23089420SMark.J.Nelson@Sun.COMelif [[ $SCM_MODE == "subversion" ]]; then
23099420SMark.J.Nelson@Sun.COM	#
23109420SMark.J.Nelson@Sun.COM	# Subversion priorities:
23119420SMark.J.Nelson@Sun.COM	# 1. CODEMGR_WS from environment
23129420SMark.J.Nelson@Sun.COM	# 2. Relative path from current directory to SVN repository root
23139420SMark.J.Nelson@Sun.COM	#
23149420SMark.J.Nelson@Sun.COM	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
23159420SMark.J.Nelson@Sun.COM		CWS=$CODEMGR_WS
23169420SMark.J.Nelson@Sun.COM	else
23179420SMark.J.Nelson@Sun.COM		svn info | while read line; do
23189420SMark.J.Nelson@Sun.COM			if [[ $line == "URL: "* ]]; then
23199420SMark.J.Nelson@Sun.COM				url=${line#URL: }
23209420SMark.J.Nelson@Sun.COM			elif [[ $line == "Repository Root: "* ]]; then
23219420SMark.J.Nelson@Sun.COM				repo=${line#Repository Root: }
23229420SMark.J.Nelson@Sun.COM			fi
23239420SMark.J.Nelson@Sun.COM		done
23249420SMark.J.Nelson@Sun.COM
232510789SEdward.Pilatowicz@Sun.COM		rel=${url#$repo}
23269420SMark.J.Nelson@Sun.COM		CWS=${PWD%$rel}
23279420SMark.J.Nelson@Sun.COM	fi
23289420SMark.J.Nelson@Sun.COMfi
23299420SMark.J.Nelson@Sun.COM
23309420SMark.J.Nelson@Sun.COM#
23319420SMark.J.Nelson@Sun.COM# If no SCM has been determined, take either the environment setting
23329420SMark.J.Nelson@Sun.COM# setting for CODEMGR_WS, or the current directory if that wasn't set.
23339420SMark.J.Nelson@Sun.COM#
23349420SMark.J.Nelson@Sun.COMif [[ -z ${CWS} ]]; then
23359420SMark.J.Nelson@Sun.COM	CWS=${CODEMGR_WS:-.}
23369420SMark.J.Nelson@Sun.COMfi
23379420SMark.J.Nelson@Sun.COM
23389420SMark.J.Nelson@Sun.COM#
23399193SMark.J.Nelson@Sun.COM# If the command line options indicate no webrev generation, either
23409193SMark.J.Nelson@Sun.COM# explicitly (-n) or implicitly (-D but not -U), then there's a whole
23419193SMark.J.Nelson@Sun.COM# ton of logic we can skip.
23429193SMark.J.Nelson@Sun.COM#
23439193SMark.J.Nelson@Sun.COM# Instead of increasing indentation, we intentionally leave this loop
23449193SMark.J.Nelson@Sun.COM# body open here, and exit via break from multiple points within.
23459193SMark.J.Nelson@Sun.COM# Search for DO_EVERYTHING below to find the break points and closure.
23469193SMark.J.Nelson@Sun.COM#
23479193SMark.J.Nelson@Sun.COMfor do_everything in 1; do
23489193SMark.J.Nelson@Sun.COM
23499193SMark.J.Nelson@Sun.COM# DO_EVERYTHING: break point
23509193SMark.J.Nelson@Sun.COMif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
23519193SMark.J.Nelson@Sun.COM	break
23529193SMark.J.Nelson@Sun.COMfi
23539193SMark.J.Nelson@Sun.COM
23549193SMark.J.Nelson@Sun.COM#
23553252Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
23563252Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
23573252Sdp#
23583252Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
23593252Sdp	parent_webrev="$codemgr_parent"
23603252Sdp	codemgr_parent="$codemgr_parent/raw_files/new"
23610Sstevel@tonic-gatefi
23620Sstevel@tonic-gate
23633252Sdpif [[ -z $wflag && -z $lflag ]]; then
23643252Sdp	shift $(($OPTIND - 1))
23650Sstevel@tonic-gate
23663252Sdp	if [[ $1 == "-" ]]; then
23673252Sdp		cat > $FLIST
23683295Sdp		flist_mode="stdin"
23693295Sdp		flist_done=1
23703295Sdp		shift
23713252Sdp	elif [[ -n $1 ]]; then
23723295Sdp		if [[ ! -r $1 ]]; then
23733252Sdp			print -u2 "$1: no such file or not readable"
23743252Sdp			usage
23753252Sdp		fi
23763252Sdp		cat $1 > $FLIST
23773295Sdp		flist_mode="file"
23783295Sdp		flist_file=$1
23793295Sdp		flist_done=1
23803295Sdp		shift
23813252Sdp	else
23823295Sdp		flist_mode="auto"
23833252Sdp	fi
23843252Sdpfi
23853252Sdp
23863252Sdp#
23873252Sdp# Before we go on to further consider -l and -w, work out which SCM we think
23883252Sdp# is in use.
23893252Sdp#
23907078Smjnelsoncase "$SCM_MODE" in
23917078Smjnelsonteamware|mercurial|subversion)
23927078Smjnelson	;;
23937078Smjnelsonunknown)
23947078Smjnelson	if [[ $flist_mode == "auto" ]]; then
23957078Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
23967078Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
23977078Smjnelson		exit 1
23987078Smjnelson	fi
23997078Smjnelson	;;
24007078Smjnelson*)
24017078Smjnelson	if [[ $flist_mode == "auto" ]]; then
24027078Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
24037078Smjnelson		exit 1
24047078Smjnelson	fi
24057078Smjnelson	;;
24067078Smjnelsonesac
24070Sstevel@tonic-gate
24083252Sdpprint -u2 "   SCM detected: $SCM_MODE"
24090Sstevel@tonic-gate
24103252Sdpif [[ -n $lflag ]]; then
24113252Sdp	#
24123252Sdp	# If the -l flag is given instead of the name of a file list,
24133252Sdp	# then generate the file list by extracting file names from a
24143252Sdp	# putback -n.
24153252Sdp	#
24163252Sdp	shift $(($OPTIND - 1))
24177078Smjnelson	if [[ $SCM_MODE == "teamware" ]]; then
24187078Smjnelson		flist_from_teamware "$*"
24197078Smjnelson	else
24207078Smjnelson		print -u2 -- "Error: -l option only applies to TeamWare"
24217078Smjnelson		exit 1
24227078Smjnelson	fi
24233252Sdp	flist_done=1
24243252Sdp	shift $#
24253252Sdpelif [[ -n $wflag ]]; then
24263252Sdp	#
24273252Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
24283252Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
24293252Sdp	# lines with blank lines as separators.  Use the SCCS comments later
24303252Sdp	# in building the index.html file.
24313252Sdp	#
24323252Sdp	shift $(($OPTIND - 1))
24333252Sdp	wxfile=$1
24343252Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
24353252Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
24363252Sdp			wxfile=$CODEMGR_WS/wx/active
24373252Sdp		fi
24383252Sdp	fi
24393252Sdp
24403252Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
24413252Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
24423252Sdp
24437078Smjnelson	if [[ ! -r $wxfile ]]; then
24447078Smjnelson		print -u2 "$wxfile: no such file or not readable"
24457078Smjnelson		usage
24467078Smjnelson	fi
24477078Smjnelson
24483252Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
24493252Sdp	flist_from_wx $wxfile
24503252Sdp	flist_done=1
24513252Sdp	if [[ -n "$*" ]]; then
24523252Sdp		shift
24533252Sdp	fi
24543295Sdpelif [[ $flist_mode == "stdin" ]]; then
24553295Sdp	print -u2 " File list from: standard input"
24563295Sdpelif [[ $flist_mode == "file" ]]; then
24573295Sdp	print -u2 " File list from: $flist_file"
24580Sstevel@tonic-gatefi
24593252Sdp
24603252Sdpif [[ $# -gt 0 ]]; then
24613295Sdp	print -u2 "WARNING: unused arguments: $*"
24620Sstevel@tonic-gatefi
24630Sstevel@tonic-gate
24649420SMark.J.Nelson@Sun.COM#
24659420SMark.J.Nelson@Sun.COM# Before we entered the DO_EVERYTHING loop, we should have already set CWS
24669420SMark.J.Nelson@Sun.COM# and CODEMGR_WS as needed.  Here, we set the parent workspace.
24679420SMark.J.Nelson@Sun.COM#
24689420SMark.J.Nelson@Sun.COM
24693252Sdpif [[ $SCM_MODE == "teamware" ]]; then
24709420SMark.J.Nelson@Sun.COM
24713252Sdp	#
24729420SMark.J.Nelson@Sun.COM	# Teamware priorities:
24733252Sdp	#
24749420SMark.J.Nelson@Sun.COM	#      1) via -p command line option
24753252Sdp	#      2) in the user environment
24763252Sdp	#      3) in the flist
24779420SMark.J.Nelson@Sun.COM	#      4) automatically based on the workspace
24783252Sdp	#
24790Sstevel@tonic-gate
24803252Sdp	#
24819420SMark.J.Nelson@Sun.COM	# For 1, codemgr_parent will already be set.  Here's 2:
24823252Sdp	#
24833252Sdp	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
24843252Sdp	    codemgr_parent=$CODEMGR_PARENT
24853252Sdp	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
24863252Sdp		print -u2 "$codemgr_parent: no such directory"
24873252Sdp		exit 1
24883252Sdp	fi
24890Sstevel@tonic-gate
24903252Sdp	#
24913252Sdp	# If we're in auto-detect mode and we haven't already gotten the file
24923252Sdp	# list, then see if we can get it by probing for wx.
24933252Sdp	#
24943295Sdp	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
24953295Sdp		if [[ ! -x $WX ]]; then
24963295Sdp			print -u2 "WARNING: wx not found!"
24973252Sdp		fi
24980Sstevel@tonic-gate
24993252Sdp		#
25003252Sdp		# We need to use wx list -w so that we get renamed files, etc.
25013252Sdp		# but only if a wx active file exists-- otherwise wx will
25023252Sdp		# hang asking us to initialize our wx information.
25033252Sdp		#
25043295Sdp		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
25053252Sdp			print -u2 " File list from: 'wx list -w' ... \c"
25063252Sdp			$WX list -w > $FLIST
25073252Sdp			$WX comments > /tmp/$$.wx_comments
25083252Sdp			wxfile=/tmp/$$.wx_comments
25093252Sdp			print -u2 "done"
25103252Sdp			flist_done=1
25113252Sdp		fi
25123252Sdp	fi
25133252Sdp
25143252Sdp	#
25153252Sdp	# If by hook or by crook we've gotten a file list by now (perhaps
25163252Sdp	# from the command line), eval it to extract environment variables from
25179420SMark.J.Nelson@Sun.COM	# it: This is method 3 for finding the parent.
25183252Sdp	#
25193252Sdp	if [[ -z $flist_done ]]; then
25203252Sdp		flist_from_teamware
25213252Sdp	fi
25229420SMark.J.Nelson@Sun.COM	env_from_flist
25233252Sdp
25243252Sdp	#
25253252Sdp	# (4) If we still don't have a value for codemgr_parent, get it
25263252Sdp	# from workspace.
25273252Sdp	#
25283252Sdp	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
25293252Sdp	if [[ ! -d $codemgr_parent ]]; then
25303252Sdp		print -u2 "$CODEMGR_PARENT: no such parent workspace"
25313252Sdp		exit 1
25323252Sdp	fi
25333252Sdp
25343252Sdp	PWS=$codemgr_parent
25357078Smjnelson
25367078Smjnelson	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
25377078Smjnelson
25387078Smjnelsonelif [[ $SCM_MODE == "mercurial" ]]; then
25397078Smjnelson	#
25407078Smjnelson	# Parent can either be specified with -p
25417078Smjnelson	# Specified with CODEMGR_PARENT in the environment
25427078Smjnelson	# or taken from hg's default path.
25437078Smjnelson	#
25447078Smjnelson
25457078Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
25467078Smjnelson		codemgr_parent=$CODEMGR_PARENT
25477078Smjnelson	fi
25487078Smjnelson
25497078Smjnelson	if [[ -z $codemgr_parent ]]; then
25507078Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
25517078Smjnelson	fi
25527078Smjnelson
25537078Smjnelson	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
25547078Smjnelson	PWS=$codemgr_parent
25557078Smjnelson
255610789SEdward.Pilatowicz@Sun.COM	#
25577078Smjnelson	# If the parent is a webrev, we want to do some things against
25587078Smjnelson	# the natural workspace parent (file list, comments, etc)
25597078Smjnelson	#
25607078Smjnelson	if [[ -n $parent_webrev ]]; then
25617078Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
25627078Smjnelson	else
25637078Smjnelson		real_parent=$PWS
25647078Smjnelson	fi
25657078Smjnelson
25667078Smjnelson	#
25677078Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
25687078Smjnelson	# flist given, we'll use it for our comments.  In the case of an
25697078Smjnelson	# explicit flist given we'll try to use it for comments for any
25707078Smjnelson	# files mentioned in the flist.
25717078Smjnelson	#
25727078Smjnelson	if [[ -z $flist_done ]]; then
25737078Smjnelson		flist_from_mercurial $CWS $real_parent
25747078Smjnelson		flist_done=1
25757078Smjnelson	fi
25767078Smjnelson
25777078Smjnelson	#
25787078Smjnelson	# If we have a file list now, pull out any variables set
25797078Smjnelson	# therein.  We do this now (rather than when we possibly use
25807078Smjnelson	# hg-active to find comments) to avoid stomping specifications
25817078Smjnelson	# in the user-specified flist.
258210789SEdward.Pilatowicz@Sun.COM	#
25837078Smjnelson	if [[ -n $flist_done ]]; then
25847078Smjnelson		env_from_flist
25857078Smjnelson	fi
25867078Smjnelson
25877078Smjnelson	#
25887078Smjnelson	# Only call hg-active if we don't have a wx formatted file already
25897078Smjnelson	#
25907078Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
25917078Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
25927078Smjnelson		hg_active_wxfile $CWS $real_parent
25937078Smjnelson		print " Done."
25947078Smjnelson	fi
259510789SEdward.Pilatowicz@Sun.COM
25967078Smjnelson	#
25977078Smjnelson	# At this point we must have a wx flist either from hg-active,
25987078Smjnelson	# or in general.  Use it to try and find our parent revision,
25997078Smjnelson	# if we don't have one.
26007078Smjnelson	#
26017078Smjnelson	if [[ -z $HG_PARENT ]]; then
26029079SVladimir.Kotal@Sun.COM		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
26037078Smjnelson	fi
26047078Smjnelson
26057078Smjnelson	#
26067078Smjnelson	# If we still don't have a parent, we must have been given a
26077078Smjnelson	# wx-style active list with no HG_PARENT specification, run
26087078Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
26097078Smjnelson	#
26107078Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
26117078Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
26129079SVladimir.Kotal@Sun.COM		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
26137078Smjnelson	elif [[ -z $HG_PARENT ]]; then
26147078Smjnelson		print -u2 "Error: Cannot discover parent revision"
26157078Smjnelson		exit 1
26167078Smjnelson	fi
26177078Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
26187078Smjnelson
26197078Smjnelson	#
26207078Smjnelson	# We only will have a real parent workspace in the case one
26217078Smjnelson	# was specified (be it an older webrev, or another checkout).
26227078Smjnelson	#
26237078Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
26247078Smjnelson
26257078Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
26267078Smjnelson		flist_from_subversion $CWS $OLDPWD
26277078Smjnelson	fi
26287078Smjnelsonelse
26297078Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
26307078Smjnelson	print -u2 "    Unknown type of SCM in use"
26317078Smjnelson    else
26327078Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
26337078Smjnelson    fi
26347078Smjnelson
26357078Smjnelson    env_from_flist
26367078Smjnelson
26377078Smjnelson    if [[ -z $CODEMGR_WS ]]; then
26387078Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
26397078Smjnelson	exit 1
26407078Smjnelson    fi
26417078Smjnelson
26427078Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
26437078Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
26447078Smjnelson	exit 1
26457078Smjnelson    fi
26467078Smjnelson
26477078Smjnelson    CWS=$CODEMGR_WS
26487078Smjnelson    PWS=$CODEMGR_PARENT
26490Sstevel@tonic-gatefi
26500Sstevel@tonic-gate
26513252Sdp#
26523252Sdp# If the user didn't specify a -i option, check to see if there is a
26533252Sdp# webrev-info file in the workspace directory.
26543252Sdp#
26553252Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
26563252Sdp	iflag=1
26573252Sdp	INCLUDE_FILE="$CWS/webrev-info"
26580Sstevel@tonic-gatefi
26590Sstevel@tonic-gate
26603252Sdpif [[ -n $iflag ]]; then
26613252Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
26623252Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
26633252Sdp		    "not readable."
26643252Sdp		exit 1
26653252Sdp	else
26663252Sdp		#
26673252Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
26683252Sdp		# PWD, so we just stash a copy in /tmp.
26693252Sdp		#
26703252Sdp		cp $INCLUDE_FILE /tmp/$$.include
26713252Sdp	fi
26720Sstevel@tonic-gatefi
26730Sstevel@tonic-gate
26749193SMark.J.Nelson@Sun.COM# DO_EVERYTHING: break point
26759193SMark.J.Nelson@Sun.COMif [[ -n $Nflag ]]; then
26769193SMark.J.Nelson@Sun.COM	break
26779193SMark.J.Nelson@Sun.COMfi
26789193SMark.J.Nelson@Sun.COM
26799193SMark.J.Nelson@Sun.COMtypeset -A itsinfo
26809193SMark.J.Nelson@Sun.COMtypeset -r its_sed_script=/tmp/$$.its_sed
26819193SMark.J.Nelson@Sun.COMvalid_prefixes=
26829193SMark.J.Nelson@Sun.COMif [[ -z $nflag ]]; then
26839193SMark.J.Nelson@Sun.COM	DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
26849193SMark.J.Nelson@Sun.COM	if [[ -n $Iflag ]]; then
26859193SMark.J.Nelson@Sun.COM		REGFILE=$ITSREG
26869193SMark.J.Nelson@Sun.COM	elif [[ -r $HOME/.its.reg ]]; then
26879193SMark.J.Nelson@Sun.COM		REGFILE=$HOME/.its.reg
26889193SMark.J.Nelson@Sun.COM	else
26899193SMark.J.Nelson@Sun.COM		REGFILE=$DEFREGFILE
26909193SMark.J.Nelson@Sun.COM	fi
26919193SMark.J.Nelson@Sun.COM	if [[ ! -r $REGFILE ]]; then
26929193SMark.J.Nelson@Sun.COM		print "ERROR: Unable to read database registry file $REGFILE"
26939193SMark.J.Nelson@Sun.COM		exit 1
26949193SMark.J.Nelson@Sun.COM	elif [[ $REGFILE != $DEFREGFILE ]]; then
26959193SMark.J.Nelson@Sun.COM		print "   its.reg from: $REGFILE"
26969193SMark.J.Nelson@Sun.COM	fi
26979193SMark.J.Nelson@Sun.COM
26989193SMark.J.Nelson@Sun.COM	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
269910789SEdward.Pilatowicz@Sun.COM
27009193SMark.J.Nelson@Sun.COM		name=${LINE%%=*}
27019193SMark.J.Nelson@Sun.COM		value="${LINE#*=}"
27029193SMark.J.Nelson@Sun.COM
27039193SMark.J.Nelson@Sun.COM		if [[ $name == PREFIX ]]; then
27049193SMark.J.Nelson@Sun.COM			p=${value}
27059193SMark.J.Nelson@Sun.COM			valid_prefixes="${p} ${valid_prefixes}"
27069193SMark.J.Nelson@Sun.COM		else
27079193SMark.J.Nelson@Sun.COM			itsinfo["${p}_${name}"]="${value}"
27089193SMark.J.Nelson@Sun.COM		fi
27099193SMark.J.Nelson@Sun.COM	done
27109193SMark.J.Nelson@Sun.COM
27119193SMark.J.Nelson@Sun.COM
27129193SMark.J.Nelson@Sun.COM	DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
27139193SMark.J.Nelson@Sun.COM	CONFFILES=$DEFCONFFILE
27149193SMark.J.Nelson@Sun.COM	if [[ -r $HOME/.its.conf ]]; then
27159193SMark.J.Nelson@Sun.COM		CONFFILES="${CONFFILES} $HOME/.its.conf"
27169193SMark.J.Nelson@Sun.COM	fi
27179193SMark.J.Nelson@Sun.COM	if [[ -n $Cflag ]]; then
27189193SMark.J.Nelson@Sun.COM		CONFFILES="${CONFFILES} ${ITSCONF}"
27199193SMark.J.Nelson@Sun.COM	fi
27209193SMark.J.Nelson@Sun.COM	its_domain=
27219193SMark.J.Nelson@Sun.COM	its_priority=
27229193SMark.J.Nelson@Sun.COM	for cf in ${CONFFILES}; do
27239193SMark.J.Nelson@Sun.COM		if [[ ! -r $cf ]]; then
27249193SMark.J.Nelson@Sun.COM			print "ERROR: Unable to read database configuration file $cf"
27259193SMark.J.Nelson@Sun.COM			exit 1
27269193SMark.J.Nelson@Sun.COM		elif [[ $cf != $DEFCONFFILE ]]; then
27279193SMark.J.Nelson@Sun.COM			print "       its.conf: reading $cf"
27289193SMark.J.Nelson@Sun.COM		fi
27299193SMark.J.Nelson@Sun.COM		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
27309193SMark.J.Nelson@Sun.COM		    eval "${LINE}"
27319193SMark.J.Nelson@Sun.COM		done
27329193SMark.J.Nelson@Sun.COM	done
27339193SMark.J.Nelson@Sun.COM
27349193SMark.J.Nelson@Sun.COM	#
27359193SMark.J.Nelson@Sun.COM	# If an information tracking system is explicitly identified by prefix,
27369193SMark.J.Nelson@Sun.COM	# we want to disregard the specified priorities and resolve it accordingly.
27379193SMark.J.Nelson@Sun.COM	#
27389193SMark.J.Nelson@Sun.COM	# To that end, we'll build a sed script to do each valid prefix in turn.
27399193SMark.J.Nelson@Sun.COM	#
27409193SMark.J.Nelson@Sun.COM	for p in ${valid_prefixes}; do
27419193SMark.J.Nelson@Sun.COM		#
27429193SMark.J.Nelson@Sun.COM		# When an informational URL was provided, translate it to a
27439193SMark.J.Nelson@Sun.COM		# hyperlink.  When omitted, simply use the prefix text.
27449193SMark.J.Nelson@Sun.COM		#
27459193SMark.J.Nelson@Sun.COM		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
27469193SMark.J.Nelson@Sun.COM			itsinfo["${p}_INFO"]=${p}
27479193SMark.J.Nelson@Sun.COM		else
27489193SMark.J.Nelson@Sun.COM			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
27499193SMark.J.Nelson@Sun.COM		fi
27509193SMark.J.Nelson@Sun.COM
27519193SMark.J.Nelson@Sun.COM		#
27529193SMark.J.Nelson@Sun.COM		# Assume that, for this invocation of webrev, all references
27539193SMark.J.Nelson@Sun.COM		# to this information tracking system should resolve through
27549193SMark.J.Nelson@Sun.COM		# the same URL.
27559193SMark.J.Nelson@Sun.COM		#
27569193SMark.J.Nelson@Sun.COM		# If the caller specified -O, then always use EXTERNAL_URL.
27579193SMark.J.Nelson@Sun.COM		#
27589193SMark.J.Nelson@Sun.COM		# Otherwise, look in the list of domains for a matching
27599193SMark.J.Nelson@Sun.COM		# INTERNAL_URL.
27609193SMark.J.Nelson@Sun.COM		#
27619193SMark.J.Nelson@Sun.COM		[[ -z $Oflag ]] && for d in ${its_domain}; do
27629193SMark.J.Nelson@Sun.COM			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
27639193SMark.J.Nelson@Sun.COM				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
27649193SMark.J.Nelson@Sun.COM				break
27659193SMark.J.Nelson@Sun.COM			fi
27669193SMark.J.Nelson@Sun.COM		done
27679193SMark.J.Nelson@Sun.COM		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
27689193SMark.J.Nelson@Sun.COM			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
27699193SMark.J.Nelson@Sun.COM		fi
27709193SMark.J.Nelson@Sun.COM
27719193SMark.J.Nelson@Sun.COM		#
27729193SMark.J.Nelson@Sun.COM		# Turn the destination URL into a hyperlink
27739193SMark.J.Nelson@Sun.COM		#
27749193SMark.J.Nelson@Sun.COM		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
27759193SMark.J.Nelson@Sun.COM
27769193SMark.J.Nelson@Sun.COM		print "/^${p}[ 	]/ {
27779193SMark.J.Nelson@Sun.COM				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27789193SMark.J.Nelson@Sun.COM				s;^${p};${itsinfo[${p}_INFO]};
27799193SMark.J.Nelson@Sun.COM			}" >> ${its_sed_script}
27809193SMark.J.Nelson@Sun.COM	done
27819193SMark.J.Nelson@Sun.COM
27829193SMark.J.Nelson@Sun.COM	#
27839193SMark.J.Nelson@Sun.COM	# The previous loop took care of explicit specification.  Now use
27849193SMark.J.Nelson@Sun.COM	# the configured priorities to attempt implicit translations.
27859193SMark.J.Nelson@Sun.COM	#
27869193SMark.J.Nelson@Sun.COM	for p in ${its_priority}; do
27879193SMark.J.Nelson@Sun.COM		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
27889193SMark.J.Nelson@Sun.COM				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
27899193SMark.J.Nelson@Sun.COM			}" >> ${its_sed_script}
27909193SMark.J.Nelson@Sun.COM	done
27919193SMark.J.Nelson@Sun.COMfi
27929193SMark.J.Nelson@Sun.COM
27939193SMark.J.Nelson@Sun.COM#
27949193SMark.J.Nelson@Sun.COM# Search for DO_EVERYTHING above for matching "for" statement
27959193SMark.J.Nelson@Sun.COM# and explanation of this terminator.
27969193SMark.J.Nelson@Sun.COM#
27979193SMark.J.Nelson@Sun.COMdone
27989193SMark.J.Nelson@Sun.COM
27993252Sdp#
28003252Sdp# Output directory.
28013252Sdp#
28023252SdpWDIR=${WDIR:-$CWS/webrev}
28030Sstevel@tonic-gate
28043252Sdp#
28058018SVladimir.Kotal@Sun.COM# Name of the webrev, derived from the workspace name or output directory;
28068018SVladimir.Kotal@Sun.COM# in the future this could potentially be an option.
28073252Sdp#
28088018SVladimir.Kotal@Sun.COMif [[ -n $oflag ]]; then
28098018SVladimir.Kotal@Sun.COM	WNAME=${WDIR##*/}
28108018SVladimir.Kotal@Sun.COMelse
28118018SVladimir.Kotal@Sun.COM	WNAME=${CWS##*/}
28128018SVladimir.Kotal@Sun.COMfi
28138018SVladimir.Kotal@Sun.COM
28148365SVladimir.Kotal@Sun.COM# Make sure remote target is well formed for remote upload/delete.
28158365SVladimir.Kotal@Sun.COMif [[ -n $Dflag || -n $Uflag ]]; then
28169079SVladimir.Kotal@Sun.COM	#
28178365SVladimir.Kotal@Sun.COM	# If remote target is not specified, build it from scratch using
28188365SVladimir.Kotal@Sun.COM	# the default values.
28199079SVladimir.Kotal@Sun.COM	#
28208365SVladimir.Kotal@Sun.COM	if [[ -z $tflag ]]; then
28218365SVladimir.Kotal@Sun.COM		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
28228365SVladimir.Kotal@Sun.COM	else
28239079SVladimir.Kotal@Sun.COM		#
28249079SVladimir.Kotal@Sun.COM		# Check upload target prefix first.
28259079SVladimir.Kotal@Sun.COM		#
28269079SVladimir.Kotal@Sun.COM		if [[ "${remote_target}" != ${rsync_prefix}* &&
28279079SVladimir.Kotal@Sun.COM		    "${remote_target}" != ${ssh_prefix}* ]]; then
28289079SVladimir.Kotal@Sun.COM			print "ERROR: invalid prefix of upload URI" \
28299079SVladimir.Kotal@Sun.COM			    "($remote_target)"
28309079SVladimir.Kotal@Sun.COM			exit 1
28319079SVladimir.Kotal@Sun.COM		fi
28329079SVladimir.Kotal@Sun.COM		#
28338365SVladimir.Kotal@Sun.COM		# If destination specification is not in the form of
28348365SVladimir.Kotal@Sun.COM		# host_spec:remote_dir then assume it is just remote hostname
28358365SVladimir.Kotal@Sun.COM		# and append a colon and destination directory formed from
28368365SVladimir.Kotal@Sun.COM		# local webrev directory name.
28379079SVladimir.Kotal@Sun.COM		#
28389079SVladimir.Kotal@Sun.COM		typeset target_no_prefix=${remote_target##*://}
28399079SVladimir.Kotal@Sun.COM		if [[ ${target_no_prefix} == *:* ]]; then
28408365SVladimir.Kotal@Sun.COM			if [[ "${remote_target}" == *: ]]; then
28419079SVladimir.Kotal@Sun.COM				remote_target=${remote_target}${WNAME}
28429079SVladimir.Kotal@Sun.COM			fi
28439079SVladimir.Kotal@Sun.COM		else
28449079SVladimir.Kotal@Sun.COM			if [[ ${target_no_prefix} == */* ]]; then
28459079SVladimir.Kotal@Sun.COM				print "ERROR: badly formed upload URI" \
28469079SVladimir.Kotal@Sun.COM					"($remote_target)"
28479079SVladimir.Kotal@Sun.COM				exit 1
28488365SVladimir.Kotal@Sun.COM			else
28499079SVladimir.Kotal@Sun.COM				remote_target=${remote_target}:${WNAME}
28508365SVladimir.Kotal@Sun.COM			fi
28518365SVladimir.Kotal@Sun.COM		fi
28528365SVladimir.Kotal@Sun.COM	fi
28539079SVladimir.Kotal@Sun.COM
28549079SVladimir.Kotal@Sun.COM	#
28559079SVladimir.Kotal@Sun.COM	# Strip trailing slash. Each upload method will deal with directory
28569079SVladimir.Kotal@Sun.COM	# specification separately.
28579079SVladimir.Kotal@Sun.COM	#
28589079SVladimir.Kotal@Sun.COM	remote_target=${remote_target%/}
28598365SVladimir.Kotal@Sun.COMfi
28608365SVladimir.Kotal@Sun.COM
28619079SVladimir.Kotal@Sun.COM#
28628365SVladimir.Kotal@Sun.COM# Option -D by itself (option -U not present) implies no webrev generation.
28639079SVladimir.Kotal@Sun.COM#
28648365SVladimir.Kotal@Sun.COMif [[ -z $Uflag && -n $Dflag ]]; then
28659079SVladimir.Kotal@Sun.COM	delete_webrev 1 1
28668018SVladimir.Kotal@Sun.COM	exit $?
28678018SVladimir.Kotal@Sun.COMfi
28683252Sdp
28699079SVladimir.Kotal@Sun.COM#
28708365SVladimir.Kotal@Sun.COM# Do not generate the webrev, just upload it or delete it.
28719079SVladimir.Kotal@Sun.COM#
28728365SVladimir.Kotal@Sun.COMif [[ -n $nflag ]]; then
28738365SVladimir.Kotal@Sun.COM	if [[ -n $Dflag ]]; then
28749079SVladimir.Kotal@Sun.COM		delete_webrev 1 1
28758365SVladimir.Kotal@Sun.COM		(( $? == 0 )) || exit $?
28768365SVladimir.Kotal@Sun.COM	fi
28778365SVladimir.Kotal@Sun.COM	if [[ -n $Uflag ]]; then
28788365SVladimir.Kotal@Sun.COM		upload_webrev
28798365SVladimir.Kotal@Sun.COM		exit $?
28808365SVladimir.Kotal@Sun.COM	fi
28818365SVladimir.Kotal@Sun.COMfi
28828365SVladimir.Kotal@Sun.COM
28835175Sjmcpif [ "${WDIR%%/*}" ]; then
28840Sstevel@tonic-gate	WDIR=$PWD/$WDIR
28850Sstevel@tonic-gatefi
28863252Sdp
28873252Sdpif [[ ! -d $WDIR ]]; then
28883252Sdp	mkdir -p $WDIR
28898365SVladimir.Kotal@Sun.COM	(( $? != 0 )) && exit 1
28903252Sdpfi
28913252Sdp
28923252Sdp#
28933252Sdp# Summarize what we're going to do.
28943252Sdp#
28957078Smjnelsonif [[ -n $CWS_REV ]]; then
28967078Smjnelson	print "      Workspace: $CWS (at $CWS_REV)"
28977078Smjnelsonelse
28987078Smjnelson	print "      Workspace: $CWS"
28997078Smjnelsonfi
29003252Sdpif [[ -n $parent_webrev ]]; then
29013252Sdp	print "Compare against: webrev at $parent_webrev"
29023252Sdpelse
29037078Smjnelson	if [[ -n $HG_PARENT ]]; then
29047078Smjnelson		hg_parent_short=`echo $HG_PARENT \
29059079SVladimir.Kotal@Sun.COM			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
29067078Smjnelson		print "Compare against: $PWS (at $hg_parent_short)"
29077078Smjnelson	else
29087078Smjnelson		print "Compare against: $PWS"
29097078Smjnelson	fi
29100Sstevel@tonic-gatefi
29110Sstevel@tonic-gate
29123252Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
29133252Sdpprint "      Output to: $WDIR"
29143252Sdp
29153252Sdp#
29160Sstevel@tonic-gate# Save the file list in the webrev dir
29173252Sdp#
29183252Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
29190Sstevel@tonic-gate
29203252Sdprm -f $WDIR/$WNAME.patch
29213252Sdprm -f $WDIR/$WNAME.ps
29223252Sdprm -f $WDIR/$WNAME.pdf
29230Sstevel@tonic-gate
29243252Sdptouch $WDIR/$WNAME.patch
29253252Sdp
29263252Sdpprint "   Output Files:"
29270Sstevel@tonic-gate
29283252Sdp#
29293252Sdp# Clean up the file list: Remove comments, blank lines and env variables.
29303252Sdp#
29319079SVladimir.Kotal@Sun.COM$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
29323252SdpFLIST=/tmp/$$.flist.clean
29333252Sdp
29343252Sdp#
29357078Smjnelson# For Mercurial, create a cache of manifest entries.
29367078Smjnelson#
29377078Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
29387078Smjnelson	#
29397078Smjnelson	# Transform the FLIST into a temporary sed script that matches
29407078Smjnelson	# relevant entries in the Mercurial manifest as follows:
29417078Smjnelson	# 1) The script will be used against the parent revision manifest,
29427078Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
29437078Smjnelson	#    keep only the old name.
29447078Smjnelson	# 2) Escape all forward slashes the filename.
29457078Smjnelson	# 3) Change the filename into another sed command that matches
29467078Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
29477078Smjnelson	#    octal digits for file permissions, space, a file type flag
29487078Smjnelson	#    character, space, the filename, end of line.
294910789SEdward.Pilatowicz@Sun.COM	# 4) Eliminate any duplicate entries.  (This can occur if a
295010789SEdward.Pilatowicz@Sun.COM	#    file has been used as the source of an hg cp and it's
295110789SEdward.Pilatowicz@Sun.COM	#    also been modified in the same changeset.)
29527078Smjnelson	#
29537078Smjnelson	SEDFILE=/tmp/$$.manifest.sed
29549079SVladimir.Kotal@Sun.COM	$SED '
29557078Smjnelson		s#^[^ ]* ##
29567078Smjnelson		s#/#\\\/#g
29577078Smjnelson		s#^.*$#/^... . &$/p#
295810789SEdward.Pilatowicz@Sun.COM	' < $FLIST | $SORT -u > $SEDFILE
29597078Smjnelson
29607078Smjnelson	#
29617078Smjnelson	# Apply the generated script to the output of "hg manifest -v"
29627078Smjnelson	# to get the relevant subset for this webrev.
29637078Smjnelson	#
29647078Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
29657078Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
29669079SVladimir.Kotal@Sun.COM	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
29677078Smjnelsonfi
29687078Smjnelson
29697078Smjnelson#
29703252Sdp# First pass through the files: generate the per-file webrev HTML-files.
29713252Sdp#
29723252Sdpcat $FLIST | while read LINE
29730Sstevel@tonic-gatedo
29740Sstevel@tonic-gate	set - $LINE
29750Sstevel@tonic-gate	P=$1
29760Sstevel@tonic-gate
29773252Sdp	#
29783252Sdp	# Normally, each line in the file list is just a pathname of a
29793252Sdp	# file that has been modified or created in the child.  A file
29803252Sdp	# that is renamed in the child workspace has two names on the
29813252Sdp	# line: new name followed by the old name.
29823252Sdp	#
29833252Sdp	oldname=""
29843252Sdp	oldpath=""
29853252Sdp	rename=
29863252Sdp	if [[ $# -eq 2 ]]; then
29870Sstevel@tonic-gate		PP=$2			# old filename
298810789SEdward.Pilatowicz@Sun.COM		if [[ -f $PP ]]; then
298910789SEdward.Pilatowicz@Sun.COM			oldname=" (copied from $PP)"
299010789SEdward.Pilatowicz@Sun.COM		else
299110789SEdward.Pilatowicz@Sun.COM			oldname=" (renamed from $PP)"
299210789SEdward.Pilatowicz@Sun.COM		fi
29933252Sdp		oldpath="$PP"
29943252Sdp		rename=1
299510789SEdward.Pilatowicz@Sun.COM		PDIR=${PP%/*}
299610789SEdward.Pilatowicz@Sun.COM		if [[ $PDIR == $PP ]]; then
29970Sstevel@tonic-gate			PDIR="."   # File at root of workspace
29980Sstevel@tonic-gate		fi
29990Sstevel@tonic-gate
30000Sstevel@tonic-gate		PF=${PP##*/}
30010Sstevel@tonic-gate
300210789SEdward.Pilatowicz@Sun.COM		DIR=${P%/*}
300310789SEdward.Pilatowicz@Sun.COM		if [[ $DIR == $P ]]; then
30040Sstevel@tonic-gate			DIR="."   # File at root of workspace
30050Sstevel@tonic-gate		fi
30063252Sdp
30070Sstevel@tonic-gate		F=${P##*/}
30083252Sdp
30090Sstevel@tonic-gate        else
301010789SEdward.Pilatowicz@Sun.COM		DIR=${P%/*}
301110789SEdward.Pilatowicz@Sun.COM		if [[ "$DIR" == "$P" ]]; then
30120Sstevel@tonic-gate			DIR="."   # File at root of workspace
30130Sstevel@tonic-gate		fi
30143252Sdp
30150Sstevel@tonic-gate		F=${P##*/}
30160Sstevel@tonic-gate
30170Sstevel@tonic-gate		PP=$P
30180Sstevel@tonic-gate		PDIR=$DIR
30190Sstevel@tonic-gate		PF=$F
30200Sstevel@tonic-gate	fi
30210Sstevel@tonic-gate
30223252Sdp	COMM=`getcomments html $P $PP`
30230Sstevel@tonic-gate
30243252Sdp	print "\t$P$oldname\n\t\t\c"
30250Sstevel@tonic-gate
30260Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
30273252Sdp	mkdir -p $WDIR/$DIR
30280Sstevel@tonic-gate
30293252Sdp	#
30307078Smjnelson	# We stash old and new files into parallel directories in $WDIR
30313252Sdp	# and do our diffs there.  This makes it possible to generate
30323252Sdp	# clean looking diffs which don't have absolute paths present.
30333252Sdp	#
30347078Smjnelson
30357078Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
30367078Smjnelson	    continue
30377078Smjnelson
30387078Smjnelson	#
30397078Smjnelson	# Keep the old PWD around, so we can safely switch back after
30407078Smjnelson	# diff generation, such that build_old_new runs in a
30417078Smjnelson	# consistent environment.
30427078Smjnelson	#
30437078Smjnelson	OWD=$PWD
30443252Sdp	cd $WDIR/raw_files
30453252Sdp	ofile=old/$PDIR/$PF
30463252Sdp	nfile=new/$DIR/$F
30473252Sdp
30483252Sdp	mv_but_nodiff=
30493252Sdp	cmp $ofile $nfile > /dev/null 2>&1
30503252Sdp	if [[ $? == 0 && $rename == 1 ]]; then
30513252Sdp		mv_but_nodiff=1
30523252Sdp	fi
30533252Sdp
30543252Sdp	#
30553252Sdp	# If we have old and new versions of the file then run the appropriate
30563252Sdp	# diffs.  This is complicated by a couple of factors:
30573252Sdp	#
30583252Sdp	#	- renames must be handled specially: we emit a 'remove'
30593252Sdp	#	  diff and an 'add' diff
30603252Sdp	#	- new files and deleted files must be handled specially
30613252Sdp	#	- Solaris patch(1m) can't cope with file creation
30623252Sdp	#	  (and hence renames) as of this writing.
30633252Sdp	#       - To make matters worse, gnu patch doesn't interpret the
30643252Sdp	#	  output of Solaris diff properly when it comes to
30653252Sdp	#	  adds and deletes.  We need to do some "cleansing"
30663252Sdp	#         transformations:
306710789SEdward.Pilatowicz@Sun.COM	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
30683252Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
30693252Sdp	#
30709079SVladimir.Kotal@Sun.COM	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
30719079SVladimir.Kotal@Sun.COM	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
30720Sstevel@tonic-gate
30733252Sdp	rm -f $WDIR/$DIR/$F.patch
30743252Sdp	if [[ -z $rename ]]; then
30755175Sjmcp		if [ ! -f "$ofile" ]; then
30763252Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
30773252Sdp			    > $WDIR/$DIR/$F.patch
30785175Sjmcp		elif [ ! -f "$nfile" ]; then
30793252Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
30803252Sdp			    > $WDIR/$DIR/$F.patch
30813252Sdp		else
30823252Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
30833252Sdp		fi
30843252Sdp	else
30853252Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
30863252Sdp		    > $WDIR/$DIR/$F.patch
30873252Sdp
30883252Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
30893252Sdp		    >> $WDIR/$DIR/$F.patch
30903252Sdp	fi
30913252Sdp
30923252Sdp	#
30933252Sdp	# Tack the patch we just made onto the accumulated patch for the
30943252Sdp	# whole wad.
30953252Sdp	#
30963252Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
30973252Sdp
30983252Sdp	print " patch\c"
30993252Sdp
31003252Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
31013252Sdp
31023252Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
31033252Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
31043252Sdp		    > $WDIR/$DIR/$F.cdiff.html
31050Sstevel@tonic-gate		print " cdiffs\c"
31060Sstevel@tonic-gate
31073252Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
31083252Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
31093252Sdp		    > $WDIR/$DIR/$F.udiff.html
31103252Sdp
31110Sstevel@tonic-gate		print " udiffs\c"
31120Sstevel@tonic-gate
31130Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
31143252Sdp			$WDIFF -c "$COMM" \
31153252Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
31163252Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
31173252Sdp			if [[ $? -eq 0 ]]; then
31183252Sdp				print " wdiffs\c"
31193252Sdp			else
31203252Sdp				print " wdiffs[fail]\c"
31213252Sdp			fi
31220Sstevel@tonic-gate		fi
31230Sstevel@tonic-gate
31243252Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
31253252Sdp		    > $WDIR/$DIR/$F.sdiff.html
31260Sstevel@tonic-gate		print " sdiffs\c"
31270Sstevel@tonic-gate
31283252Sdp		print " frames\c"
31290Sstevel@tonic-gate
31300Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
31310Sstevel@tonic-gate
31323252Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
31333252Sdp
31343252Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
31353252Sdp		# renamed file: may also have differences
31363252Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
31373252Sdp	elif [[ -f $nfile ]]; then
31380Sstevel@tonic-gate		# new file: count added lines
31393252Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
31403252Sdp	elif [[ -f $ofile ]]; then
31410Sstevel@tonic-gate		# old file: count deleted lines
31423252Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
31430Sstevel@tonic-gate	fi
31440Sstevel@tonic-gate
31453252Sdp	#
31463252Sdp	# Now we generate the postscript for this file.  We generate diffs
31473252Sdp	# only in the event that there is delta, or the file is new (it seems
31483252Sdp	# tree-killing to print out the contents of deleted files).
31493252Sdp	#
31503252Sdp	if [[ -f $nfile ]]; then
31513252Sdp		ocr=$ofile
31523252Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
31533252Sdp
31543252Sdp		if [[ -z $mv_but_nodiff ]]; then
31553252Sdp			textcomm=`getcomments text $P $PP`
31563295Sdp			if [[ -x $CODEREVIEW ]]; then
31573295Sdp				$CODEREVIEW -y "$textcomm" \
31583295Sdp				    -e $ocr $nfile \
31593295Sdp				    > /tmp/$$.psfile 2>/dev/null &&
31603295Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
31613295Sdp				if [[ $? -eq 0 ]]; then
31623295Sdp					print " ps\c"
31633295Sdp				else
31643295Sdp					print " ps[fail]\c"
31653295Sdp				fi
31663252Sdp			fi
31673252Sdp		fi
31683252Sdp	fi
31693252Sdp
31707078Smjnelson	if [[ -f $ofile ]]; then
31717078Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
31720Sstevel@tonic-gate		print " old\c"
31730Sstevel@tonic-gate	fi
31740Sstevel@tonic-gate
31753252Sdp	if [[ -f $nfile ]]; then
31763252Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
31770Sstevel@tonic-gate		print " new\c"
31780Sstevel@tonic-gate	fi
31790Sstevel@tonic-gate
31807078Smjnelson	cd $OWD
31817078Smjnelson
31823252Sdp	print
31830Sstevel@tonic-gatedone
31840Sstevel@tonic-gate
31853252Sdpframe_nav_js > $WDIR/ancnav.js
31863252Sdpframe_navigation > $WDIR/ancnav.html
31873252Sdp
31883295Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
31893295Sdp	print " Generating PDF: Skipped: no output available"
31903295Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
31913295Sdp	print " Generating PDF: \c"
31923295Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
31933295Sdp	print "Done."
31943295Sdpelse
31953295Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
31963295Sdpfi
31970Sstevel@tonic-gate
31985175Sjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
31995175Sjmcp# delete it - prevent accidental publishing of closed source
32005175Sjmcp
32015175Sjmcpif [[ -n "$Oflag" ]]; then
32028365SVladimir.Kotal@Sun.COM	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
32035175Sjmcpfi
32045175Sjmcp
32050Sstevel@tonic-gate# Now build the index.html file that contains
32060Sstevel@tonic-gate# links to the source files and their diffs.
32070Sstevel@tonic-gate
32080Sstevel@tonic-gatecd $CWS
32090Sstevel@tonic-gate
32100Sstevel@tonic-gate# Save total changed lines for Code Inspection.
32113252Sdpprint "$TOTL" > $WDIR/TotalChangedLines
32120Sstevel@tonic-gate
32133252Sdpprint "     index.html: \c"
32140Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
32150Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
32160Sstevel@tonic-gateexec 1<&-			# Close stdout.
32170Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
32180Sstevel@tonic-gate
32193252Sdpprint "$HTML<head>$STDHEAD"
32203252Sdpprint "<title>$WNAME</title>"
32213252Sdpprint "</head>"
32223252Sdpprint "<body id=\"SUNWwebrev\">"
32233252Sdpprint "<div class=\"summary\">"
32243252Sdpprint "<h2>Code Review for $WNAME</h2>"
32253252Sdp
32263252Sdpprint "<table>"
32273252Sdp
32283252Sdp#
32297078Smjnelson# Get the preparer's name:
32307078Smjnelson#
32317078Smjnelson# If the SCM detected is Mercurial, and the configuration property
32327078Smjnelson# ui.username is available, use that, but be careful to properly escape
32337078Smjnelson# angle brackets (HTML syntax characters) in the email address.
32347078Smjnelson#
32357078Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
32367078Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
32373252Sdp#
32387078Smjnelsonpreparer=
32397078Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
32407078Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
32417078Smjnelson	if [[ -n "$preparer" ]]; then
32427078Smjnelson		preparer="$(echo "$preparer" | html_quote)"
32437078Smjnelson	fi
32443252Sdpfi
32457078Smjnelsonif [[ -z "$preparer" ]]; then
32467078Smjnelson	preparer=$(
32477078Smjnelson	    $PERL -e '
32487078Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
32497078Smjnelson	        if ($login) {
32507078Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
32517078Smjnelson	            printf "%s (%s)\n", $gcos, $login;
32527078Smjnelson	        } else {
32537078Smjnelson	            printf "(unknown)\n";
32547078Smjnelson	        }
32557078Smjnelson	')
32567078Smjnelsonfi
32577078Smjnelson
325810738SJames.McPherson@Sun.COMPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
325910738SJames.McPherson@Sun.COMprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
32607078Smjnelsonprint "<tr><th>Workspace:</th><td>$CWS"
32617078Smjnelsonif [[ -n $CWS_REV ]]; then
32627078Smjnelson	print "(at $CWS_REV)"
32637078Smjnelsonfi
32647078Smjnelsonprint "</td></tr>"
32653252Sdpprint "<tr><th>Compare against:</th><td>"
32663252Sdpif [[ -n $parent_webrev ]]; then
32673252Sdp	print "webrev at $parent_webrev"
32683252Sdpelse
32693252Sdp	print "$PWS"
32707078Smjnelson	if [[ -n $hg_parent_short ]]; then
32717078Smjnelson		print "(at $hg_parent_short)"
32727078Smjnelson	fi
32733252Sdpfi
32743252Sdpprint "</td></tr>"
32753252Sdpprint "<tr><th>Summary of changes:</th><td>"
32763252SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
32773252Sdpprint "</td></tr>"
32780Sstevel@tonic-gate
32793252Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
32809011SLubomir.Sedlacik@Sun.COM	wpatch_url="$(print $WNAME.patch | url_encode)"
32813252Sdp	print "<tr><th>Patch of changes:</th><td>"
32829011SLubomir.Sedlacik@Sun.COM	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
32833252Sdpfi
32843252Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
32859011SLubomir.Sedlacik@Sun.COM	wpdf_url="$(print $WNAME.pdf | url_encode)"
32863252Sdp	print "<tr><th>Printable review:</th><td>"
32879011SLubomir.Sedlacik@Sun.COM	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
32883252Sdpfi
32890Sstevel@tonic-gate
32903252Sdpif [[ -n "$iflag" ]]; then
32913252Sdp	print "<tr><th>Author comments:</th><td><div>"
32923252Sdp	cat /tmp/$$.include
32933252Sdp	print "</div></td></tr>"
32943252Sdpfi
32953252Sdpprint "</table>"
32963252Sdpprint "</div>"
32973252Sdp
32983252Sdp#
32993252Sdp# Second pass through the files: generate the rest of the index file
33003252Sdp#
33013252Sdpcat $FLIST | while read LINE
33020Sstevel@tonic-gatedo
33030Sstevel@tonic-gate	set - $LINE
33040Sstevel@tonic-gate	P=$1
33050Sstevel@tonic-gate
33063252Sdp	if [[ $# == 2 ]]; then
33070Sstevel@tonic-gate		PP=$2
33087078Smjnelson		oldname="$PP"
33090Sstevel@tonic-gate	else
33100Sstevel@tonic-gate		PP=$P
33113252Sdp		oldname=""
33123252Sdp	fi
33133252Sdp
33147078Smjnelson	mv_but_nodiff=
33157078Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
33167078Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
33177078Smjnelson		mv_but_nodiff=1
33187078Smjnelson	fi
33197078Smjnelson
33203252Sdp	DIR=${P%/*}
33213252Sdp	if [[ $DIR == $P ]]; then
33223252Sdp		DIR="."   # File at root of workspace
33230Sstevel@tonic-gate	fi
33240Sstevel@tonic-gate
33250Sstevel@tonic-gate	# Avoid processing the same file twice.
33260Sstevel@tonic-gate	# It's possible for renamed files to
33270Sstevel@tonic-gate	# appear twice in the file list
33280Sstevel@tonic-gate
33290Sstevel@tonic-gate	F=$WDIR/$P
33300Sstevel@tonic-gate
33313252Sdp	print "<p>"
33320Sstevel@tonic-gate
33330Sstevel@tonic-gate	# If there's a diffs file, make diffs links
33340Sstevel@tonic-gate
33353252Sdp	if [[ -f $F.cdiff.html ]]; then
33369011SLubomir.Sedlacik@Sun.COM		cdiff_url="$(print $P.cdiff.html | url_encode)"
33379011SLubomir.Sedlacik@Sun.COM		udiff_url="$(print $P.udiff.html | url_encode)"
33389011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$cdiff_url\">Cdiffs</a>"
33399011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$udiff_url\">Udiffs</a>"
33403252Sdp
33413252Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
33429011SLubomir.Sedlacik@Sun.COM			wdiff_url="$(print $P.wdiff.html | url_encode)"
33439011SLubomir.Sedlacik@Sun.COM			print "<a href=\"$wdiff_url\">Wdiffs</a>"
33443252Sdp		fi
33450Sstevel@tonic-gate
33469011SLubomir.Sedlacik@Sun.COM		sdiff_url="$(print $P.sdiff.html | url_encode)"
33479011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$sdiff_url\">Sdiffs</a>"
33489011SLubomir.Sedlacik@Sun.COM
33499011SLubomir.Sedlacik@Sun.COM		frames_url="$(print $P.frames.html | url_encode)"
33509011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$frames_url\">Frames</a>"
33513252Sdp	else
33523252Sdp		print " ------ ------ ------"
33533252Sdp
33543252Sdp		if [[ -x $WDIFF ]]; then
33553252Sdp			print " ------"
33560Sstevel@tonic-gate		fi
33570Sstevel@tonic-gate
33583252Sdp		print " ------"
33593252Sdp	fi
33603252Sdp
33613252Sdp	# If there's an old file, make the link
33620Sstevel@tonic-gate
33633252Sdp	if [[ -f $F-.html ]]; then
33649011SLubomir.Sedlacik@Sun.COM		oldfile_url="$(print $P-.html | url_encode)"
33659011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$oldfile_url\">Old</a>"
33663252Sdp	else
33673252Sdp		print " ---"
33683252Sdp	fi
33693252Sdp
33703252Sdp	# If there's an new file, make the link
33713252Sdp
33723252Sdp	if [[ -f $F.html ]]; then
33739011SLubomir.Sedlacik@Sun.COM		newfile_url="$(print $P.html | url_encode)"
33749011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$newfile_url\">New</a>"
33750Sstevel@tonic-gate	else
33763252Sdp		print " ---"
33773252Sdp	fi
33783252Sdp
33793252Sdp	if [[ -f $F.patch ]]; then
33809011SLubomir.Sedlacik@Sun.COM		patch_url="$(print $P.patch | url_encode)"
33819011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$patch_url\">Patch</a>"
33823252Sdp	else
33833252Sdp		print " -----"
33843252Sdp	fi
33850Sstevel@tonic-gate
33863252Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
33879011SLubomir.Sedlacik@Sun.COM		rawfiles_url="$(print raw_files/new/$P | url_encode)"
33889011SLubomir.Sedlacik@Sun.COM		print "<a href=\"$rawfiles_url\">Raw</a>"
33893252Sdp	else
33903252Sdp		print " ---"
33913252Sdp	fi
33923252Sdp
33937078Smjnelson	print "<b>$P</b>"
33947078Smjnelson
33957078Smjnelson	# For renamed files, clearly state whether or not they are modified
339610789SEdward.Pilatowicz@Sun.COM	if [[ -f "$oldname" ]]; then
33977078Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
339810789SEdward.Pilatowicz@Sun.COM			print "<i>(copied from $oldname)</i>"
33997078Smjnelson		else
340010789SEdward.Pilatowicz@Sun.COM			print "<i>(copied and modified from $oldname)</i>"
340110789SEdward.Pilatowicz@Sun.COM		fi
340210789SEdward.Pilatowicz@Sun.COM	elif [[ -n "$oldname" ]]; then
340310789SEdward.Pilatowicz@Sun.COM		if [[ -n "$mv_but_nodiff" ]]; then
340410789SEdward.Pilatowicz@Sun.COM			print "<i>(renamed from $oldname)</i>"
340510789SEdward.Pilatowicz@Sun.COM		else
340610789SEdward.Pilatowicz@Sun.COM			print "<i>(renamed and modified from $oldname)</i>"
34077078Smjnelson		fi
34087078Smjnelson	fi
34097078Smjnelson
34107078Smjnelson	# If there's an old file, but no new file, the file was deleted
34117078Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
34127078Smjnelson		print " <i>(deleted)</i>"
34137078Smjnelson	fi
34140Sstevel@tonic-gate
34153252Sdp	#
34165175Sjmcp	# Check for usr/closed and deleted_files/usr/closed
34173252Sdp	#
34183252Sdp	if [ ! -z "$Oflag" ]; then
34195175Sjmcp		if [[ $P == usr/closed/* || \
34205175Sjmcp		    $P == deleted_files/usr/closed/* ]]; then
34213252Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
34223252Sdp			    "this review</i>"
34230Sstevel@tonic-gate		fi
34240Sstevel@tonic-gate	fi
34250Sstevel@tonic-gate
34263252Sdp	print "</p>"
34270Sstevel@tonic-gate	# Insert delta comments
34280Sstevel@tonic-gate
34293252Sdp	print "<blockquote><pre>"
34303252Sdp	getcomments html $P $PP
34313252Sdp	print "</pre>"
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate	# Add additional comments comment
34340Sstevel@tonic-gate
34353252Sdp	print "<!-- Add comments to explain changes in $P here -->"
34360Sstevel@tonic-gate
34370Sstevel@tonic-gate	# Add count of changes.
34380Sstevel@tonic-gate
34393252Sdp	if [[ -f $F.count ]]; then
34400Sstevel@tonic-gate	    cat $F.count
34410Sstevel@tonic-gate	    rm $F.count
34420Sstevel@tonic-gate	fi
34437078Smjnelson
34447078Smjnelson	if [[ $SCM_MODE == "teamware" ||
34457078Smjnelson	    $SCM_MODE == "mercurial" ||
34467078Smjnelson	    $SCM_MODE == "unknown" ]]; then
34477078Smjnelson
34487078Smjnelson		# Include warnings for important file mode situations:
34497078Smjnelson		# 1) New executable files
34507078Smjnelson		# 2) Permission changes of any kind
34517078Smjnelson		# 3) Existing executable files
34527078Smjnelson
34537078Smjnelson		old_mode=
34547078Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
34557078Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
34567078Smjnelson		fi
34577078Smjnelson
34587078Smjnelson		new_mode=
34597078Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
34607078Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
34617078Smjnelson		fi
34627078Smjnelson
34637078Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
34647078Smjnelson			print "<span class=\"chmod\">"
34657078Smjnelson			print "<p>new executable file: mode $new_mode</p>"
34667078Smjnelson			print "</span>"
34677078Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
34687078Smjnelson		    "$old_mode" != "$new_mode" ]]; then
34697078Smjnelson			print "<span class=\"chmod\">"
34707078Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
34717078Smjnelson			print "</span>"
34727078Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
34737078Smjnelson			print "<span class=\"chmod\">"
34747078Smjnelson			print "<p>executable file: mode $new_mode</p>"
34757078Smjnelson			print "</span>"
34767078Smjnelson		fi
34777078Smjnelson	fi
34787078Smjnelson
34793252Sdp	print "</blockquote>"
34800Sstevel@tonic-gatedone
34810Sstevel@tonic-gate
34823252Sdpprint
34833252Sdpprint
34846922Smjnelsonprint "<hr></hr>"
34853252Sdpprint "<p style=\"font-size: small\">"
34867298SMark.J.Nelson@Sun.COMprint "This code review page was prepared using <b>$0</b>."
34873252Sdpprint "Webrev is maintained by the <a href=\"http://www.opensolaris.org\">"
34883252Sdpprint "OpenSolaris</a> project.  The latest version may be obtained"
34893696Sfr80241print "<a href=\"http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
34903252Sdpprint "</body>"
34913252Sdpprint "</html>"
34920Sstevel@tonic-gate
34930Sstevel@tonic-gateexec 1<&-			# Close FD 1.
34940Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
34950Sstevel@tonic-gateexec 3<&-			# close FD 3.
34960Sstevel@tonic-gate
34973252Sdpprint "Done."
34988018SVladimir.Kotal@Sun.COM
34999079SVladimir.Kotal@Sun.COM#
35008365SVladimir.Kotal@Sun.COM# If remote deletion was specified and fails do not continue.
35019079SVladimir.Kotal@Sun.COM#
35028365SVladimir.Kotal@Sun.COMif [[ -n $Dflag ]]; then
35039079SVladimir.Kotal@Sun.COM	delete_webrev 1 1
35048365SVladimir.Kotal@Sun.COM	(( $? == 0 )) || exit $?
35058365SVladimir.Kotal@Sun.COMfi
35068365SVladimir.Kotal@Sun.COM
35078018SVladimir.Kotal@Sun.COMif [[ -n $Uflag ]]; then
35088018SVladimir.Kotal@Sun.COM	upload_webrev
35098018SVladimir.Kotal@Sun.COM	exit $?
35108018SVladimir.Kotal@Sun.COMfi
3511