xref: /titanic_41/usr/src/tools/scripts/webrev.sh (revision 932a1e132b4d74b503715c64f9e5863a6549f7f5)
148fe8920SMark J. Nelson#!/usr/bin/ksh93 -p
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
6daaffb31Sdp# Common Development and Distribution License (the "License").
7daaffb31Sdp# You may not use this file except in compliance with the License.
87c478bd9Sstevel@tonic-gate#
97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate# and limitations under the License.
137c478bd9Sstevel@tonic-gate#
147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate#
207c478bd9Sstevel@tonic-gate# CDDL HEADER END
217c478bd9Sstevel@tonic-gate#
229a70fc3bSMark J. Nelson
237c478bd9Sstevel@tonic-gate#
2478add226Sjmcp# Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
252f54b716SRichard Lowe# Copyright 2008, 2010, Richard Lowe
267646c8f3SMarcel Telka# Copyright 2012 Marcel Telka <marcel@telka.sk>
273ba097dbSBart Coddens# Copyright 2014 Bart Coddens <bart.coddens@gmail.com>
28*932a1e13SYuri Pankov# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
290c108ed9SYuri Pankov#
302f54b716SRichard Lowe
31cdf0c1d5Smjnelson#
32daaffb31Sdp# This script takes a file list and a workspace and builds a set of html files
33daaffb31Sdp# suitable for doing a code review of source changes via a web page.
34daaffb31Sdp# Documentation is available via the manual page, webrev.1, or just
35daaffb31Sdp# type 'webrev -h'.
367c478bd9Sstevel@tonic-gate#
37daaffb31Sdp# Acknowledgements to contributors to webrev are listed in the webrev(1)
38daaffb31Sdp# man page.
397c478bd9Sstevel@tonic-gate#
40daaffb31Sdp
417c478bd9Sstevel@tonic-gateREMOVED_COLOR=brown
427c478bd9Sstevel@tonic-gateCHANGED_COLOR=blue
437c478bd9Sstevel@tonic-gateNEW_COLOR=blue
447c478bd9Sstevel@tonic-gate
45daaffb31SdpHTML='<?xml version="1.0"?>
46daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
47daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
48daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
49daaffb31Sdp
50daaffb31SdpFRAMEHTML='<?xml version="1.0"?>
51daaffb31Sdp<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
52daaffb31Sdp    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
53daaffb31Sdp<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
54daaffb31Sdp
55cac38512SmjnelsonSTDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
56e66b80afSRobert Mustacchi<meta http-equiv="Content-Type" content="text/xhtml;charset=utf-8"></meta>
57cac38512Smjnelson<meta http-equiv="Pragma" content="no-cache"></meta>
58cac38512Smjnelson<meta http-equiv="Expires" content="-1"></meta>
59daaffb31Sdp<!--
60daaffb31Sdp   Note to customizers: the body of the webrev is IDed as SUNWwebrev
61daaffb31Sdp   to allow easy overriding by users of webrev via the userContent.css
62daaffb31Sdp   mechanism available in some browsers.
63daaffb31Sdp
64daaffb31Sdp   For example, to have all "removed" information be red instead of
65daaffb31Sdp   brown, set a rule in your userContent.css file like:
66daaffb31Sdp
67daaffb31Sdp       body#SUNWwebrev span.removed { color: red ! important; }
68daaffb31Sdp-->
69daaffb31Sdp<style type="text/css" media="screen">
70daaffb31Sdpbody {
71daaffb31Sdp    background-color: #eeeeee;
72daaffb31Sdp}
73daaffb31Sdphr {
74daaffb31Sdp    border: none 0;
75daaffb31Sdp    border-top: 1px solid #aaa;
76daaffb31Sdp    height: 1px;
77daaffb31Sdp}
78daaffb31Sdpdiv.summary {
79daaffb31Sdp    font-size: .8em;
80daaffb31Sdp    border-bottom: 1px solid #aaa;
81daaffb31Sdp    padding-left: 1em;
82daaffb31Sdp    padding-right: 1em;
83daaffb31Sdp}
84daaffb31Sdpdiv.summary h2 {
85daaffb31Sdp    margin-bottom: 0.3em;
86daaffb31Sdp}
87daaffb31Sdpdiv.summary table th {
88daaffb31Sdp    text-align: right;
89daaffb31Sdp    vertical-align: top;
90daaffb31Sdp    white-space: nowrap;
91daaffb31Sdp}
92daaffb31Sdpspan.lineschanged {
93daaffb31Sdp    font-size: 0.7em;
94daaffb31Sdp}
95daaffb31Sdpspan.oldmarker {
96daaffb31Sdp    color: red;
97daaffb31Sdp    font-size: large;
98daaffb31Sdp    font-weight: bold;
99daaffb31Sdp}
100daaffb31Sdpspan.newmarker {
101daaffb31Sdp    color: green;
102daaffb31Sdp    font-size: large;
103daaffb31Sdp    font-weight: bold;
104daaffb31Sdp}
105daaffb31Sdpspan.removed {
106daaffb31Sdp    color: brown;
107daaffb31Sdp}
108daaffb31Sdpspan.changed {
109daaffb31Sdp    color: blue;
110daaffb31Sdp}
111daaffb31Sdpspan.new {
112daaffb31Sdp    color: blue;
113daaffb31Sdp    font-weight: bold;
114daaffb31Sdp}
115cdf0c1d5Smjnelsonspan.chmod {
116cdf0c1d5Smjnelson    font-size: 0.7em;
117cdf0c1d5Smjnelson    color: #db7800;
118cdf0c1d5Smjnelson}
119daaffb31Sdpa.print { font-size: x-small; }
120daaffb31Sdpa:hover { background-color: #ffcc99; }
121daaffb31Sdp</style>
122daaffb31Sdp
123daaffb31Sdp<style type="text/css" media="print">
124daaffb31Sdppre { font-size: 0.8em; font-family: courier, monospace; }
125daaffb31Sdpspan.removed { color: #444; font-style: italic }
126daaffb31Sdpspan.changed { font-weight: bold; }
127daaffb31Sdpspan.new { font-weight: bold; }
128daaffb31Sdpspan.newmarker { font-size: 1.2em; font-weight: bold; }
129daaffb31Sdpspan.oldmarker { font-size: 1.2em; font-weight: bold; }
130daaffb31Sdpa.print {display: none}
131daaffb31Sdphr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
132daaffb31Sdp</style>
133daaffb31Sdp'
134daaffb31Sdp
135daaffb31Sdp#
136daaffb31Sdp# UDiffs need a slightly different CSS rule for 'new' items (we don't
137daaffb31Sdp# want them to be bolded as we do in cdiffs or sdiffs).
138daaffb31Sdp#
139daaffb31SdpUDIFFCSS='
140daaffb31Sdp<style type="text/css" media="screen">
141daaffb31Sdpspan.new {
142daaffb31Sdp    color: blue;
143daaffb31Sdp    font-weight: normal;
144daaffb31Sdp}
145daaffb31Sdp</style>
146daaffb31Sdp'
147daaffb31Sdp
148b0088928SVladimir Kotal#
1490c108ed9SYuri Pankov# CSS for the HTML version of the man pages.
1500c108ed9SYuri Pankov#
1510c108ed9SYuri PankovMANCSS='
1520c108ed9SYuri Pankovhtml { max-width: 880px; margin-left: 1em; }
1530c108ed9SYuri Pankovbody { font-size: smaller; font-family: Helvetica,Arial,sans-serif; }
1540c108ed9SYuri Pankovh1 { margin-bottom: 1ex; font-size: 110%; margin-left: -4ex; }
1550c108ed9SYuri Pankovh2 { margin-bottom: 1ex; font-size: 105%; margin-left: -2ex; }
1560c108ed9SYuri Pankovtable { width: 100%; margin-top: 0ex; margin-bottom: 0ex; }
1570c108ed9SYuri Pankovtd { vertical-align: top; }
1580c108ed9SYuri Pankovblockquote { margin-left: 5ex; margin-top: 0ex; margin-bottom: 0ex; }
1590c108ed9SYuri Pankovdiv.section { margin-bottom: 2ex; margin-left: 5ex; }
1600c108ed9SYuri Pankovtable.foot { font-size: smaller; margin-top: 1em;
1610c108ed9SYuri Pankov    border-top: 1px dotted #dddddd; }
1620c108ed9SYuri Pankovtd.foot-date { width: 50%; }
1630c108ed9SYuri Pankovtd.foot-os { width: 50%; text-align: right; }
1640c108ed9SYuri Pankovtable.head { font-size: smaller; margin-bottom: 1em;
1650c108ed9SYuri Pankov    border-bottom: 1px dotted #dddddd; }
1660c108ed9SYuri Pankovtd.head-ltitle { width: 10%; }
1670c108ed9SYuri Pankovtd.head-vol { width: 80%; text-align: center; }
1680c108ed9SYuri Pankovtd.head-rtitle { width: 10%; text-align: right; }
1690c108ed9SYuri Pankov.emph { font-style: italic; font-weight: normal; }
1700c108ed9SYuri Pankov.symb { font-style: normal; font-weight: bold; }
1710c108ed9SYuri Pankov.lit { font-style: normal; font-weight: normal; font-family: monospace; }
1720c108ed9SYuri Pankovi.addr { font-weight: normal; }
1730c108ed9SYuri Pankovi.arg { font-weight: normal; }
1740c108ed9SYuri Pankovb.cmd { font-style: normal; }
1750c108ed9SYuri Pankovb.config { font-style: normal; }
1760c108ed9SYuri Pankovb.diag { font-style: normal; }
1770c108ed9SYuri Pankovi.farg { font-weight: normal; }
1780c108ed9SYuri Pankovi.file { font-weight: normal; }
1790c108ed9SYuri Pankovb.flag { font-style: normal; }
1800c108ed9SYuri Pankovb.fname { font-style: normal; }
1810c108ed9SYuri Pankovi.ftype { font-weight: normal; }
1820c108ed9SYuri Pankovb.includes { font-style: normal; }
1830c108ed9SYuri Pankovi.link-sec { font-weight: normal; }
1840c108ed9SYuri Pankovb.macro { font-style: normal; }
1850c108ed9SYuri Pankovb.name { font-style: normal; }
1860c108ed9SYuri Pankovi.ref-book { font-weight: normal; }
1870c108ed9SYuri Pankovi.ref-issue { font-weight: normal; }
1880c108ed9SYuri Pankovi.ref-jrnl { font-weight: normal; }
1890c108ed9SYuri Pankovspan.ref-title { text-decoration: underline; }
1900c108ed9SYuri Pankovspan.type { font-style: italic; font-weight: normal; }
1910c108ed9SYuri Pankovb.utility { font-style: normal; }
1920c108ed9SYuri Pankovb.var { font-style: normal; }
1930c108ed9SYuri Pankovdd.list-ohang { margin-left: 0ex; }
1940c108ed9SYuri Pankovul.list-bul { list-style-type: disc; padding-left: 1em; }
1950c108ed9SYuri Pankovul.list-dash { list-style-type: none; padding-left: 0em; }
1960c108ed9SYuri Pankovli.list-dash:before { content: "\2014  "; }
1970c108ed9SYuri Pankovul.list-hyph { list-style-type: none; padding-left: 0em; }
1980c108ed9SYuri Pankovli.list-hyph:before { content: "\2013  "; }
1990c108ed9SYuri Pankovul.list-item { list-style-type: none; padding-left: 0em; }
2000c108ed9SYuri Pankovol.list-enum { padding-left: 2em; }
2010c108ed9SYuri Pankov'
2020c108ed9SYuri Pankov
2030c108ed9SYuri Pankov#
204b0088928SVladimir Kotal# Display remote target with prefix and trailing slash.
205b0088928SVladimir Kotal#
206b0088928SVladimir Kotalfunction print_upload_header
207b0088928SVladimir Kotal{
208b0088928SVladimir Kotal	typeset -r prefix=$1
209b0088928SVladimir Kotal	typeset display_target
210b0088928SVladimir Kotal
211b0088928SVladimir Kotal	if [[ -z $tflag ]]; then
212b0088928SVladimir Kotal		display_target=${prefix}${remote_target}
213b0088928SVladimir Kotal	else
214b0088928SVladimir Kotal		display_target=${remote_target}
215b0088928SVladimir Kotal	fi
216b0088928SVladimir Kotal
217b0088928SVladimir Kotal	if [[ ${display_target} != */ ]]; then
218b0088928SVladimir Kotal		display_target=${display_target}/
219b0088928SVladimir Kotal	fi
220b0088928SVladimir Kotal
221b0088928SVladimir Kotal	print "      Upload to: ${display_target}\n" \
222b0088928SVladimir Kotal	    "     Uploading: \c"
223b0088928SVladimir Kotal}
224b0088928SVladimir Kotal
225b0088928SVladimir Kotal#
22602d26c39SVladimir Kotal# Upload the webrev via rsync. Return 0 on success, 1 on error.
227b0088928SVladimir Kotal#
228ba44d8a2SVladimir Kotalfunction rsync_upload
22902d26c39SVladimir Kotal{
230b0088928SVladimir Kotal	if (( $# != 2 )); then
231b0088928SVladimir Kotal		print "\nERROR: rsync_upload: wrong usage ($#)"
232b0088928SVladimir Kotal		exit 1
23302d26c39SVladimir Kotal	fi
23402d26c39SVladimir Kotal
235b0088928SVladimir Kotal	typeset -r dst=$1
236b0088928SVladimir Kotal	integer -r print_err_msg=$2
23702d26c39SVladimir Kotal
238b0088928SVladimir Kotal	print_upload_header ${rsync_prefix}
239b0088928SVladimir Kotal	print "rsync ... \c"
2408a34f8dcSVladimir Kotal	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
241b0088928SVladimir Kotal	if [[ -z $err_msg ]]; then
242b0088928SVladimir Kotal		print "\nERROR: rsync_upload: cannot create temporary file"
243b0088928SVladimir Kotal		return 1
244b0088928SVladimir Kotal	fi
245b0088928SVladimir Kotal	#
246b0088928SVladimir Kotal	# The source directory must end with a slash in order to copy just
247b0088928SVladimir Kotal	# directory contents, not the whole directory.
248b0088928SVladimir Kotal	#
249b0088928SVladimir Kotal	typeset src_dir=$WDIR
250b0088928SVladimir Kotal	if [[ ${src_dir} != */ ]]; then
251b0088928SVladimir Kotal		src_dir=${src_dir}/
252b0088928SVladimir Kotal	fi
253b0088928SVladimir Kotal	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
25402d26c39SVladimir Kotal	if (( $? != 0 )); then
255b0088928SVladimir Kotal		if (( ${print_err_msg} > 0 )); then
256b0088928SVladimir Kotal			print "Failed.\nERROR: rsync failed"
257b0088928SVladimir Kotal			print "src dir: '${src_dir}'\ndst dir: '$dst'"
258b0088928SVladimir Kotal			print "error messages:"
259b0088928SVladimir Kotal			$SED 's/^/> /' $err_msg
260b0088928SVladimir Kotal			rm -f $err_msg
261b0088928SVladimir Kotal		fi
26202d26c39SVladimir Kotal		return 1
26302d26c39SVladimir Kotal	fi
26402d26c39SVladimir Kotal
265b0088928SVladimir Kotal	rm -f $err_msg
26602d26c39SVladimir Kotal	print "Done."
26702d26c39SVladimir Kotal	return 0
26802d26c39SVladimir Kotal}
26902d26c39SVladimir Kotal
270b0088928SVladimir Kotal#
271b0088928SVladimir Kotal# Create directories on remote host using SFTP. Return 0 on success,
272b0088928SVladimir Kotal# 1 on failure.
273b0088928SVladimir Kotal#
274b0088928SVladimir Kotalfunction remote_mkdirs
275b0088928SVladimir Kotal{
276b0088928SVladimir Kotal	typeset -r dir_spec=$1
2779d3952abSVladimir Kotal	typeset -r host_spec=$2
278b0088928SVladimir Kotal
279b0088928SVladimir Kotal	#
280b0088928SVladimir Kotal	# If the supplied path is absolute we assume all directories are
281b0088928SVladimir Kotal	# created, otherwise try to create all directories in the path
282b0088928SVladimir Kotal	# except the last one which will be created by scp.
283b0088928SVladimir Kotal	#
284b0088928SVladimir Kotal	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
285b0088928SVladimir Kotal		print "mkdirs \c"
286b0088928SVladimir Kotal		#
287b0088928SVladimir Kotal		# Remove the last directory from directory specification.
288b0088928SVladimir Kotal		#
289b0088928SVladimir Kotal		typeset -r dirs_mk=${dir_spec%/*}
2908a34f8dcSVladimir Kotal		typeset -r batch_file_mkdir=$( $MKTEMP \
2918a34f8dcSVladimir Kotal		    /tmp/webrev_mkdir.XXXXXX )
292b0088928SVladimir Kotal		if [[ -z $batch_file_mkdir ]]; then
293b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
294b0088928SVladimir Kotal			    "cannot create temporary file for batch file"
295b0088928SVladimir Kotal			return 1
296b0088928SVladimir Kotal		fi
297b0088928SVladimir Kotal                OLDIFS=$IFS
298b0088928SVladimir Kotal                IFS=/
299b0088928SVladimir Kotal		typeset dir
300b0088928SVladimir Kotal                for dir in ${dirs_mk}; do
301b0088928SVladimir Kotal			#
302b0088928SVladimir Kotal			# Use the '-' prefix to ignore mkdir errors in order
303b0088928SVladimir Kotal			# to avoid an error in case the directory already
304b0088928SVladimir Kotal			# exists. We check the directory with chdir to be sure
305b0088928SVladimir Kotal			# there is one.
306b0088928SVladimir Kotal			#
307b0088928SVladimir Kotal                        print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
308b0088928SVladimir Kotal                        print "chdir ${dir}" >> ${batch_file_mkdir}
309b0088928SVladimir Kotal                done
310b0088928SVladimir Kotal                IFS=$OLDIFS
3118a34f8dcSVladimir Kotal		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
312b0088928SVladimir Kotal		if [[ -z ${sftp_err_msg} ]]; then
313b0088928SVladimir Kotal			print "\nERROR: remote_mkdirs:" \
314b0088928SVladimir Kotal			    "cannot create temporary file for error messages"
315b0088928SVladimir Kotal			return 1
316b0088928SVladimir Kotal		fi
317b0088928SVladimir Kotal		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
318b0088928SVladimir Kotal		if (( $? != 0 )); then
319b0088928SVladimir Kotal			print "\nERROR: failed to create remote directories"
320b0088928SVladimir Kotal			print "error messages:"
321b0088928SVladimir Kotal			$SED 's/^/> /' ${sftp_err_msg}
322b0088928SVladimir Kotal			rm -f ${sftp_err_msg} ${batch_file_mkdir}
323b0088928SVladimir Kotal			return 1
324b0088928SVladimir Kotal		fi
325b0088928SVladimir Kotal		rm -f ${sftp_err_msg} ${batch_file_mkdir}
326b0088928SVladimir Kotal	fi
327b0088928SVladimir Kotal
328b0088928SVladimir Kotal	return 0
329b0088928SVladimir Kotal}
330b0088928SVladimir Kotal
331b0088928SVladimir Kotal#
33202d26c39SVladimir Kotal# Upload the webrev via SSH. Return 0 on success, 1 on error.
333b0088928SVladimir Kotal#
334ba44d8a2SVladimir Kotalfunction ssh_upload
33502d26c39SVladimir Kotal{
33602d26c39SVladimir Kotal	if (( $# != 1 )); then
337b0088928SVladimir Kotal		print "\nERROR: ssh_upload: wrong number of arguments"
338b0088928SVladimir Kotal		exit 1
33902d26c39SVladimir Kotal	fi
34002d26c39SVladimir Kotal
34102d26c39SVladimir Kotal	typeset dst=$1
34202d26c39SVladimir Kotal	typeset -r host_spec=${dst%%:*}
343ba44d8a2SVladimir Kotal	typeset -r dir_spec=${dst#*:}
34402d26c39SVladimir Kotal
345b0088928SVladimir Kotal	#
346b0088928SVladimir Kotal	# Display the upload information before calling delete_webrev
347b0088928SVladimir Kotal	# because it will also print its progress.
348b0088928SVladimir Kotal	#
349b0088928SVladimir Kotal	print_upload_header ${ssh_prefix}
350b0088928SVladimir Kotal
351b0088928SVladimir Kotal	#
352b0088928SVladimir Kotal	# If the deletion was explicitly requested there is no need
353b0088928SVladimir Kotal	# to perform it again.
354b0088928SVladimir Kotal	#
355ba44d8a2SVladimir Kotal	if [[ -z $Dflag ]]; then
356b0088928SVladimir Kotal		#
357b0088928SVladimir Kotal		# We do not care about return value because this might be
358b0088928SVladimir Kotal		# the first time this directory is uploaded.
359b0088928SVladimir Kotal		#
360ba44d8a2SVladimir Kotal		delete_webrev 0
36102d26c39SVladimir Kotal	fi
36202d26c39SVladimir Kotal
363b0088928SVladimir Kotal	#
364b0088928SVladimir Kotal	# Create remote directories. Any error reporting will be done
365b0088928SVladimir Kotal	# in remote_mkdirs function.
366b0088928SVladimir Kotal	#
3679d3952abSVladimir Kotal	remote_mkdirs ${dir_spec} ${host_spec}
36802d26c39SVladimir Kotal	if (( $? != 0 )); then
36902d26c39SVladimir Kotal		return 1
37002d26c39SVladimir Kotal	fi
37102d26c39SVladimir Kotal
372b0088928SVladimir Kotal	print "upload ... \c"
3738a34f8dcSVladimir Kotal	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
374b0088928SVladimir Kotal	if [[ -z ${scp_err_msg} ]]; then
375b0088928SVladimir Kotal		print "\nERROR: ssh_upload:" \
376b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
377b0088928SVladimir Kotal		return 1
378b0088928SVladimir Kotal	fi
37902d26c39SVladimir Kotal	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
380b0088928SVladimir Kotal		$WDIR $dst 2>${scp_err_msg}
38102d26c39SVladimir Kotal	if (( $? != 0 )); then
382b0088928SVladimir Kotal		print "Failed.\nERROR: scp failed"
383b0088928SVladimir Kotal		print "src dir: '$WDIR'\ndst dir: '$dst'"
384b0088928SVladimir Kotal		print "error messages:"
385b0088928SVladimir Kotal		$SED 's/^/> /' ${scp_err_msg}
386b0088928SVladimir Kotal		rm -f ${scp_err_msg}
38702d26c39SVladimir Kotal		return 1
38802d26c39SVladimir Kotal	fi
38902d26c39SVladimir Kotal
390b0088928SVladimir Kotal	rm -f ${scp_err_msg}
39102d26c39SVladimir Kotal	print "Done."
39202d26c39SVladimir Kotal	return 0
39302d26c39SVladimir Kotal}
39402d26c39SVladimir Kotal
39502d26c39SVladimir Kotal#
396ba44d8a2SVladimir Kotal# Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
397b0088928SVladimir Kotal# on failure. If first argument is 1 then perform the check of sftp return
398b0088928SVladimir Kotal# value otherwise ignore it. If second argument is present it means this run
399b0088928SVladimir Kotal# only performs deletion.
400ba44d8a2SVladimir Kotal#
401ba44d8a2SVladimir Kotalfunction delete_webrev
402ba44d8a2SVladimir Kotal{
403b0088928SVladimir Kotal	if (( $# < 1 )); then
404b0088928SVladimir Kotal		print "delete_webrev: wrong number of arguments"
405b0088928SVladimir Kotal		exit 1
406ba44d8a2SVladimir Kotal	fi
407ba44d8a2SVladimir Kotal
408b0088928SVladimir Kotal	integer -r check=$1
409b0088928SVladimir Kotal	integer delete_only=0
410b0088928SVladimir Kotal	if (( $# == 2 )); then
411b0088928SVladimir Kotal		delete_only=1
412b0088928SVladimir Kotal	fi
413b0088928SVladimir Kotal
414b0088928SVladimir Kotal	#
415ba44d8a2SVladimir Kotal	# Strip the transport specification part of remote target first.
416b0088928SVladimir Kotal	#
417ba44d8a2SVladimir Kotal	typeset -r stripped_target=${remote_target##*://}
418ba44d8a2SVladimir Kotal	typeset -r host_spec=${stripped_target%%:*}
419ba44d8a2SVladimir Kotal	typeset -r dir_spec=${stripped_target#*:}
420ba44d8a2SVladimir Kotal	typeset dir_rm
421ba44d8a2SVladimir Kotal
422b0088928SVladimir Kotal	#
423ba44d8a2SVladimir Kotal	# Do not accept an absolute path.
424b0088928SVladimir Kotal	#
425ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == /* ]]; then
426ba44d8a2SVladimir Kotal		return 1
427ba44d8a2SVladimir Kotal	fi
428ba44d8a2SVladimir Kotal
429b0088928SVladimir Kotal	#
430ba44d8a2SVladimir Kotal	# Strip the ending slash.
431b0088928SVladimir Kotal	#
432ba44d8a2SVladimir Kotal	if [[ ${dir_spec} == */ ]]; then
433ba44d8a2SVladimir Kotal		dir_rm=${dir_spec%%/}
434ba44d8a2SVladimir Kotal	else
435ba44d8a2SVladimir Kotal		dir_rm=${dir_spec}
436ba44d8a2SVladimir Kotal	fi
437ba44d8a2SVladimir Kotal
438b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
439b0088928SVladimir Kotal		print "       Removing: \c"
440b0088928SVladimir Kotal	else
441b0088928SVladimir Kotal		print "rmdir \c"
442b0088928SVladimir Kotal	fi
443ba44d8a2SVladimir Kotal	if [[ -z "$dir_rm" ]]; then
444b0088928SVladimir Kotal		print "\nERROR: empty directory for removal"
445ba44d8a2SVladimir Kotal		return 1
446ba44d8a2SVladimir Kotal	fi
447ba44d8a2SVladimir Kotal
448b0088928SVladimir Kotal	#
449ba44d8a2SVladimir Kotal	# Prepare batch file.
450b0088928SVladimir Kotal	#
4518a34f8dcSVladimir Kotal	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
452ba44d8a2SVladimir Kotal	if [[ -z $batch_file_rm ]]; then
453b0088928SVladimir Kotal		print "\nERROR: delete_webrev: cannot create temporary file"
454ba44d8a2SVladimir Kotal		return 1
455ba44d8a2SVladimir Kotal	fi
456ba44d8a2SVladimir Kotal	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
457ba44d8a2SVladimir Kotal
458b0088928SVladimir Kotal	#
459ba44d8a2SVladimir Kotal	# Perform remote deletion and remove the batch file.
460b0088928SVladimir Kotal	#
4618a34f8dcSVladimir Kotal	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
462b0088928SVladimir Kotal	if [[ -z ${sftp_err_msg} ]]; then
463b0088928SVladimir Kotal		print "\nERROR: delete_webrev:" \
464b0088928SVladimir Kotal		    "cannot create temporary file for error messages"
465b0088928SVladimir Kotal		return 1
466b0088928SVladimir Kotal	fi
467b0088928SVladimir Kotal	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
468ba44d8a2SVladimir Kotal	integer -r ret=$?
469ba44d8a2SVladimir Kotal	rm -f $batch_file_rm
470ba44d8a2SVladimir Kotal	if (( $ret != 0 && $check > 0 )); then
471b0088928SVladimir Kotal		print "Failed.\nERROR: failed to remove remote directories"
472b0088928SVladimir Kotal		print "error messages:"
473b0088928SVladimir Kotal		$SED 's/^/> /' ${sftp_err_msg}
474b0088928SVladimir Kotal		rm -f ${sftp_err_msg}
475ba44d8a2SVladimir Kotal		return $ret
476ba44d8a2SVladimir Kotal	fi
477b0088928SVladimir Kotal	rm -f ${sftp_err_msg}
478b0088928SVladimir Kotal	if (( ${delete_only} > 0 )); then
479ba44d8a2SVladimir Kotal		print "Done."
480b0088928SVladimir Kotal	fi
481ba44d8a2SVladimir Kotal
482ba44d8a2SVladimir Kotal	return 0
483ba44d8a2SVladimir Kotal}
484ba44d8a2SVladimir Kotal
485ba44d8a2SVladimir Kotal#
48602d26c39SVladimir Kotal# Upload webrev to remote site
48702d26c39SVladimir Kotal#
488ba44d8a2SVladimir Kotalfunction upload_webrev
48902d26c39SVladimir Kotal{
490b0088928SVladimir Kotal	integer ret
49102d26c39SVladimir Kotal
49202d26c39SVladimir Kotal	if [[ ! -d "$WDIR" ]]; then
493b0088928SVladimir Kotal		print "\nERROR: webrev directory '$WDIR' does not exist"
49402d26c39SVladimir Kotal		return 1
49502d26c39SVladimir Kotal	fi
49602d26c39SVladimir Kotal
497b0088928SVladimir Kotal	#
49802d26c39SVladimir Kotal	# Perform a late check to make sure we do not upload closed source
49902d26c39SVladimir Kotal	# to remote target when -n is used. If the user used custom remote
50002d26c39SVladimir Kotal	# target he probably knows what he is doing.
501b0088928SVladimir Kotal	#
50202d26c39SVladimir Kotal	if [[ -n $nflag && -z $tflag ]]; then
503ba44d8a2SVladimir Kotal		$FIND $WDIR -type d -name closed \
50402d26c39SVladimir Kotal			| $GREP closed >/dev/null
50502d26c39SVladimir Kotal		if (( $? == 0 )); then
506b0088928SVladimir Kotal			print "\nERROR: directory '$WDIR' contains" \
507b0088928SVladimir Kotal			    "\"closed\" directory"
50802d26c39SVladimir Kotal			return 1
50902d26c39SVladimir Kotal		fi
51002d26c39SVladimir Kotal	fi
51102d26c39SVladimir Kotal
512b0088928SVladimir Kotal
513b0088928SVladimir Kotal	#
514b0088928SVladimir Kotal	# We have the URI for remote destination now so let's start the upload.
515b0088928SVladimir Kotal	#
51602d26c39SVladimir Kotal	if [[ -n $tflag ]]; then
51702d26c39SVladimir Kotal		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
518b0088928SVladimir Kotal			rsync_upload ${remote_target##$rsync_prefix} 1
519b0088928SVladimir Kotal			ret=$?
520b0088928SVladimir Kotal			return $ret
52102d26c39SVladimir Kotal		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
52202d26c39SVladimir Kotal			ssh_upload ${remote_target##$ssh_prefix}
523b0088928SVladimir Kotal			ret=$?
524b0088928SVladimir Kotal			return $ret
52502d26c39SVladimir Kotal		fi
52602d26c39SVladimir Kotal	else
527b0088928SVladimir Kotal		#
528b0088928SVladimir Kotal		# Try rsync first and fallback to SSH in case it fails.
529b0088928SVladimir Kotal		#
530b0088928SVladimir Kotal		rsync_upload ${remote_target} 0
531b0088928SVladimir Kotal		ret=$?
532b0088928SVladimir Kotal		if (( $ret != 0 )); then
533b0088928SVladimir Kotal			print "Failed. (falling back to SSH)"
534ba44d8a2SVladimir Kotal			ssh_upload ${remote_target}
535b0088928SVladimir Kotal			ret=$?
53602d26c39SVladimir Kotal		fi
537b0088928SVladimir Kotal		return $ret
53802d26c39SVladimir Kotal	fi
53902d26c39SVladimir Kotal}
54002d26c39SVladimir Kotal
541daaffb31Sdp#
542371d72daSLubomir Sedlacik# input_cmd | url_encode | output_cmd
543371d72daSLubomir Sedlacik#
544371d72daSLubomir Sedlacik# URL-encode (percent-encode) reserved characters as defined in RFC 3986.
545371d72daSLubomir Sedlacik#
546371d72daSLubomir Sedlacik# Reserved characters are: :/?#[]@!$&'()*+,;=
547371d72daSLubomir Sedlacik#
548371d72daSLubomir Sedlacik# While not a reserved character itself, percent '%' is reserved by definition
549371d72daSLubomir Sedlacik# so encode it first to avoid recursive transformation, and skip '/' which is
550371d72daSLubomir Sedlacik# a path delimiter.
551371d72daSLubomir Sedlacik#
55225cc4e45SVladimir Kotal# The quotation character is deliberately not escaped in order to make
55325cc4e45SVladimir Kotal# the substitution work with GNU sed.
55425cc4e45SVladimir Kotal#
555371d72daSLubomir Sedlacikfunction url_encode
556371d72daSLubomir Sedlacik{
557b0088928SVladimir Kotal	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
558371d72daSLubomir Sedlacik	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
559371d72daSLubomir Sedlacik	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
560371d72daSLubomir Sedlacik	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
56125cc4e45SVladimir Kotal	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
562371d72daSLubomir Sedlacik	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
563371d72daSLubomir Sedlacik}
564371d72daSLubomir Sedlacik
565371d72daSLubomir Sedlacik#
566daaffb31Sdp# input_cmd | html_quote | output_cmd
567daaffb31Sdp# or
568daaffb31Sdp# html_quote filename | output_cmd
5697c478bd9Sstevel@tonic-gate#
5707c478bd9Sstevel@tonic-gate# Make a piece of source code safe for display in an HTML <pre> block.
5717c478bd9Sstevel@tonic-gate#
5727c478bd9Sstevel@tonic-gatehtml_quote()
5737c478bd9Sstevel@tonic-gate{
574b0088928SVladimir Kotal	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
5757c478bd9Sstevel@tonic-gate}
5767c478bd9Sstevel@tonic-gate
577daaffb31Sdp#
5788bcea973SRichard Lowe# Trim a digest-style revision to a conventionally readable yet useful length
5798bcea973SRichard Lowe#
5808bcea973SRichard Lowetrim_digest()
5818bcea973SRichard Lowe{
5828bcea973SRichard Lowe	typeset digest=$1
5838bcea973SRichard Lowe
5848bcea973SRichard Lowe	echo $digest | $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'
5858bcea973SRichard Lowe}
5868bcea973SRichard Lowe
5878bcea973SRichard Lowe#
5880fd2682eSMark J. Nelson# input_cmd | its2url | output_cmd
589daaffb31Sdp#
5900fd2682eSMark J. Nelson# Scan for information tracking system references and insert <a> links to the
5910fd2682eSMark J. Nelson# relevant databases.
592daaffb31Sdp#
5930fd2682eSMark J. Nelsonits2url()
5947c478bd9Sstevel@tonic-gate{
5950fd2682eSMark J. Nelson	$SED -f ${its_sed_script}
596daaffb31Sdp}
597daaffb31Sdp
5987c478bd9Sstevel@tonic-gate#
599daaffb31Sdp# strip_unchanged <infile> | output_cmd
6007c478bd9Sstevel@tonic-gate#
601daaffb31Sdp# Removes chunks of sdiff documents that have not changed. This makes it
602daaffb31Sdp# easier for a code reviewer to find the bits that have changed.
6037c478bd9Sstevel@tonic-gate#
604daaffb31Sdp# Deleted lines of text are replaced by a horizontal rule. Some
605daaffb31Sdp# identical lines are retained before and after the changed lines to
606daaffb31Sdp# provide some context.  The number of these lines is controlled by the
607cdf0c1d5Smjnelson# variable C in the $AWK script below.
608daaffb31Sdp#
609daaffb31Sdp# The script detects changed lines as any line that has a "<span class="
610daaffb31Sdp# string embedded (unchanged lines have no particular class and are not
611daaffb31Sdp# part of a <span>).  Blank lines (without a sequence number) are also
612daaffb31Sdp# detected since they flag lines that have been inserted or deleted.
613daaffb31Sdp#
614daaffb31Sdpstrip_unchanged()
615daaffb31Sdp{
616cdf0c1d5Smjnelson	$AWK '
617daaffb31Sdp	BEGIN	{ C = c = 20 }
618cdf0c1d5Smjnelson	NF == 0 || /<span class="/ {
619daaffb31Sdp		if (c > C) {
620daaffb31Sdp			c -= C
621daaffb31Sdp			inx = 0
622daaffb31Sdp			if (c > C) {
623cac38512Smjnelson				print "\n</pre><hr></hr><pre>"
624daaffb31Sdp				inx = c % C
625daaffb31Sdp				c = C
626daaffb31Sdp			}
627daaffb31Sdp
628daaffb31Sdp			for (i = 0; i < c; i++)
629daaffb31Sdp				print ln[(inx + i) % C]
630daaffb31Sdp		}
631daaffb31Sdp		c = 0;
632daaffb31Sdp		print
633daaffb31Sdp		next
634daaffb31Sdp	}
635daaffb31Sdp	{	if (c >= C) {
636daaffb31Sdp			ln[c % C] = $0
637daaffb31Sdp			c++;
638daaffb31Sdp			next;
639daaffb31Sdp		}
640daaffb31Sdp		c++;
641daaffb31Sdp		print
642daaffb31Sdp	}
643cac38512Smjnelson	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
644daaffb31Sdp
645daaffb31Sdp	' $1
646daaffb31Sdp}
647daaffb31Sdp
648daaffb31Sdp#
649daaffb31Sdp# sdiff_to_html
650daaffb31Sdp#
651daaffb31Sdp# This function takes two files as arguments, obtains their diff, and
652daaffb31Sdp# processes the diff output to present the files as an HTML document with
653daaffb31Sdp# the files displayed side-by-side, differences shown in color.  It also
654daaffb31Sdp# takes a delta comment, rendered as an HTML snippet, as the third
655daaffb31Sdp# argument.  The function takes two files as arguments, then the name of
656daaffb31Sdp# file, the path, and the comment.  The HTML will be delivered on stdout,
657daaffb31Sdp# e.g.
658daaffb31Sdp#
659daaffb31Sdp#   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
660daaffb31Sdp#         new/usr/src/tools/scripts/webrev.sh \
661daaffb31Sdp#         webrev.sh usr/src/tools/scripts \
662daaffb31Sdp#         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
663daaffb31Sdp#          1234567</a> my bugid' > <file>.html
664daaffb31Sdp#
665daaffb31Sdp# framed_sdiff() is then called which creates $2.frames.html
666daaffb31Sdp# in the webrev tree.
667daaffb31Sdp#
668daaffb31Sdp# FYI: This function is rather unusual in its use of awk.  The initial
669daaffb31Sdp# diff run produces conventional diff output showing changed lines mixed
670daaffb31Sdp# with editing codes.  The changed lines are ignored - we're interested in
671daaffb31Sdp# the editing codes, e.g.
6727c478bd9Sstevel@tonic-gate#
6737c478bd9Sstevel@tonic-gate#      8c8
6747c478bd9Sstevel@tonic-gate#      57a61
6757c478bd9Sstevel@tonic-gate#      63c66,76
6767c478bd9Sstevel@tonic-gate#      68,93d80
6777c478bd9Sstevel@tonic-gate#      106d90
6787c478bd9Sstevel@tonic-gate#      108,110d91
6797c478bd9Sstevel@tonic-gate#
680daaffb31Sdp#  These editing codes are parsed by the awk script and used to generate
681daaffb31Sdp#  another awk script that generates HTML, e.g the above lines would turn
682daaffb31Sdp#  into something like this:
6837c478bd9Sstevel@tonic-gate#
6847c478bd9Sstevel@tonic-gate#      BEGIN { printf "<pre>\n" }
6857c478bd9Sstevel@tonic-gate#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
686daaffb31Sdp#      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
6877c478bd9Sstevel@tonic-gate#      NR==8           {wl("#7A7ADD");next}
6887c478bd9Sstevel@tonic-gate#      NR==54          {wl("#7A7ADD");sp(3);next}
6897c478bd9Sstevel@tonic-gate#      NR==56          {wl("#7A7ADD");next}
6907c478bd9Sstevel@tonic-gate#      NR==57          {wl("black");printf "\n"; next}
6917c478bd9Sstevel@tonic-gate#        :               :
6927c478bd9Sstevel@tonic-gate#
693daaffb31Sdp#  This script is then run on the original source file to generate the
694daaffb31Sdp#  HTML that corresponds to the source file.
6957c478bd9Sstevel@tonic-gate#
696daaffb31Sdp#  The two HTML files are then combined into a single piece of HTML that
697daaffb31Sdp#  uses an HTML table construct to present the files side by side.  You'll
698daaffb31Sdp#  notice that the changes are color-coded:
6997c478bd9Sstevel@tonic-gate#
7007c478bd9Sstevel@tonic-gate#   black     - unchanged lines
7017c478bd9Sstevel@tonic-gate#   blue      - changed lines
7027c478bd9Sstevel@tonic-gate#   bold blue - new lines
7037c478bd9Sstevel@tonic-gate#   brown     - deleted lines
7047c478bd9Sstevel@tonic-gate#
705daaffb31Sdp#  Blank lines are inserted in each file to keep unchanged lines in sync
706daaffb31Sdp#  (side-by-side).  This format is familiar to users of sdiff(1) or
707daaffb31Sdp#  Teamware's filemerge tool.
708daaffb31Sdp#
709daaffb31Sdpsdiff_to_html()
710daaffb31Sdp{
7117c478bd9Sstevel@tonic-gate	diff -b $1 $2 > /tmp/$$.diffs
7127c478bd9Sstevel@tonic-gate
713daaffb31Sdp	TNAME=$3
714daaffb31Sdp	TPATH=$4
715daaffb31Sdp	COMMENT=$5
716daaffb31Sdp
7177c478bd9Sstevel@tonic-gate	#
7187c478bd9Sstevel@tonic-gate	#  Now we have the diffs, generate the HTML for the old file.
7197c478bd9Sstevel@tonic-gate	#
720cdf0c1d5Smjnelson	$AWK '
7217c478bd9Sstevel@tonic-gate	BEGIN	{
7227c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
723daaffb31Sdp		printf "function removed() "
724daaffb31Sdp		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
725daaffb31Sdp		printf "function changed() "
726daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
727daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
7287c478bd9Sstevel@tonic-gate}
7297c478bd9Sstevel@tonic-gate	/^</	{next}
7307c478bd9Sstevel@tonic-gate	/^>/	{next}
7317c478bd9Sstevel@tonic-gate	/^---/	{next}
732daaffb31Sdp
7337c478bd9Sstevel@tonic-gate	{
7347c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
7357c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
7367c478bd9Sstevel@tonic-gate		if (a[1] == 0) {
7377c478bd9Sstevel@tonic-gate			n = split(a[2], r, /,/);
7387c478bd9Sstevel@tonic-gate			if (n == 1)
7397c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
7407c478bd9Sstevel@tonic-gate			else
7417c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
7427c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
7437c478bd9Sstevel@tonic-gate			next
7447c478bd9Sstevel@tonic-gate		}
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[1]
7477c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
7487c478bd9Sstevel@tonic-gate		s = r[1];
7497c478bd9Sstevel@tonic-gate		if (n == 1)
7507c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
7517c478bd9Sstevel@tonic-gate		else {
7527c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
7537c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
7547c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
7557c478bd9Sstevel@tonic-gate		}
7567c478bd9Sstevel@tonic-gate		next
7577c478bd9Sstevel@tonic-gate	}
7587c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
7597c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7607c478bd9Sstevel@tonic-gate		n1 = r[1]
7617c478bd9Sstevel@tonic-gate		n2 = r[2]
7627c478bd9Sstevel@tonic-gate		if (n == 1)
763daaffb31Sdp			printf "NR==%s\t\t{removed(); next}\n" , n1
7647c478bd9Sstevel@tonic-gate		else
765daaffb31Sdp			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
7667c478bd9Sstevel@tonic-gate		next
7677c478bd9Sstevel@tonic-gate	}
7687c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
7697c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
7707c478bd9Sstevel@tonic-gate		n1 = r[1]
7717c478bd9Sstevel@tonic-gate		n2 = r[2]
7727c478bd9Sstevel@tonic-gate		final = n2
7737c478bd9Sstevel@tonic-gate		d1 = 0
7747c478bd9Sstevel@tonic-gate		if (n == 1)
775daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
7767c478bd9Sstevel@tonic-gate		else {
7777c478bd9Sstevel@tonic-gate			d1 = n2 - n1
778daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
7797c478bd9Sstevel@tonic-gate		}
7807c478bd9Sstevel@tonic-gate		m = split(a[2], r, /,/);
7817c478bd9Sstevel@tonic-gate		n1 = r[1]
7827c478bd9Sstevel@tonic-gate		n2 = r[2]
7837c478bd9Sstevel@tonic-gate		if (m > 1) {
7847c478bd9Sstevel@tonic-gate			d2  = n2 - n1
7857c478bd9Sstevel@tonic-gate			if (d2 > d1) {
7867c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
7877c478bd9Sstevel@tonic-gate				printf "sp(%d);", d2 - d1
7887c478bd9Sstevel@tonic-gate			}
7897c478bd9Sstevel@tonic-gate		}
7907c478bd9Sstevel@tonic-gate		printf "next}\n" ;
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate		next
7937c478bd9Sstevel@tonic-gate	}
7947c478bd9Sstevel@tonic-gate	}
7957c478bd9Sstevel@tonic-gate
796daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
797daaffb31Sdp	' /tmp/$$.diffs > /tmp/$$.file1
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate	#
8007c478bd9Sstevel@tonic-gate	#  Now generate the HTML for the new file
8017c478bd9Sstevel@tonic-gate	#
802cdf0c1d5Smjnelson	$AWK '
8037c478bd9Sstevel@tonic-gate	BEGIN	{
8047c478bd9Sstevel@tonic-gate		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
805daaffb31Sdp		printf "function new() "
806daaffb31Sdp		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
807daaffb31Sdp		printf "function changed() "
808daaffb31Sdp		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
809daaffb31Sdp		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
8107c478bd9Sstevel@tonic-gate	}
811daaffb31Sdp
8127c478bd9Sstevel@tonic-gate	/^</	{next}
8137c478bd9Sstevel@tonic-gate	/^>/	{next}
8147c478bd9Sstevel@tonic-gate	/^---/	{next}
815daaffb31Sdp
8167c478bd9Sstevel@tonic-gate	{
8177c478bd9Sstevel@tonic-gate	split($1, a, /[cad]/) ;
8187c478bd9Sstevel@tonic-gate	if (index($1, "d")) {
8197c478bd9Sstevel@tonic-gate		if (a[2] == 0) {
8207c478bd9Sstevel@tonic-gate			n = split(a[1], r, /,/);
8217c478bd9Sstevel@tonic-gate			if (n == 1)
8227c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(1)}\n"
8237c478bd9Sstevel@tonic-gate			else
8247c478bd9Sstevel@tonic-gate				printf "BEGIN\t\t{sp(%d)}\n",\
8257c478bd9Sstevel@tonic-gate				(r[2] - r[1]) + 1
8267c478bd9Sstevel@tonic-gate			next
8277c478bd9Sstevel@tonic-gate		}
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate		printf "NR==%s\t\t{", a[2]
8307c478bd9Sstevel@tonic-gate		n = split(a[1], r, /,/);
8317c478bd9Sstevel@tonic-gate		s = r[1];
8327c478bd9Sstevel@tonic-gate		if (n == 1)
8337c478bd9Sstevel@tonic-gate			printf "bl();printf \"\\n\"; next}\n"
8347c478bd9Sstevel@tonic-gate		else {
8357c478bd9Sstevel@tonic-gate			n = r[2] - r[1]
8367c478bd9Sstevel@tonic-gate			printf "bl();sp(%d);next}\n",\
8377c478bd9Sstevel@tonic-gate			(r[2] - r[1]) + 1
8387c478bd9Sstevel@tonic-gate		}
8397c478bd9Sstevel@tonic-gate		next
8407c478bd9Sstevel@tonic-gate	}
8417c478bd9Sstevel@tonic-gate	if (index($1, "a")) {
8427c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
8437c478bd9Sstevel@tonic-gate		n1 = r[1]
8447c478bd9Sstevel@tonic-gate		n2 = r[2]
8457c478bd9Sstevel@tonic-gate		if (n == 1)
846daaffb31Sdp			printf "NR==%s\t\t{new() ; next}\n" , n1
8477c478bd9Sstevel@tonic-gate		else
848daaffb31Sdp			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
8497c478bd9Sstevel@tonic-gate		next
8507c478bd9Sstevel@tonic-gate	}
8517c478bd9Sstevel@tonic-gate	if (index($1, "c")) {
8527c478bd9Sstevel@tonic-gate		n = split(a[2], r, /,/);
8537c478bd9Sstevel@tonic-gate		n1 = r[1]
8547c478bd9Sstevel@tonic-gate		n2 = r[2]
8557c478bd9Sstevel@tonic-gate		final = n2
8567c478bd9Sstevel@tonic-gate		d2 = 0;
8577c478bd9Sstevel@tonic-gate		if (n == 1) {
8587c478bd9Sstevel@tonic-gate			final = n1
859daaffb31Sdp			printf "NR==%s\t\t{changed();" , n1
8607c478bd9Sstevel@tonic-gate		} else {
8617c478bd9Sstevel@tonic-gate			d2 = n2 - n1
862daaffb31Sdp			printf "NR==%s,NR==%s\t{changed();" , n1, n2
8637c478bd9Sstevel@tonic-gate		}
8647c478bd9Sstevel@tonic-gate		m = split(a[1], r, /,/);
8657c478bd9Sstevel@tonic-gate		n1 = r[1]
8667c478bd9Sstevel@tonic-gate		n2 = r[2]
8677c478bd9Sstevel@tonic-gate		if (m > 1) {
8687c478bd9Sstevel@tonic-gate			d1  = n2 - n1
8697c478bd9Sstevel@tonic-gate			if (d1 > d2) {
8707c478bd9Sstevel@tonic-gate				if (n > 1) printf "if (NR==%d)", final
8717c478bd9Sstevel@tonic-gate				printf "sp(%d);", d1 - d2
8727c478bd9Sstevel@tonic-gate			}
8737c478bd9Sstevel@tonic-gate		}
8747c478bd9Sstevel@tonic-gate		printf "next}\n" ;
8757c478bd9Sstevel@tonic-gate		next
8767c478bd9Sstevel@tonic-gate	}
8777c478bd9Sstevel@tonic-gate	}
878daaffb31Sdp	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
8797c478bd9Sstevel@tonic-gate	' /tmp/$$.diffs > /tmp/$$.file2
8807c478bd9Sstevel@tonic-gate
881daaffb31Sdp	#
882cdf0c1d5Smjnelson	# Post-process the HTML files by running them back through $AWK
883daaffb31Sdp	#
884cdf0c1d5Smjnelson	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
8857c478bd9Sstevel@tonic-gate
886cdf0c1d5Smjnelson	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
8877c478bd9Sstevel@tonic-gate
888daaffb31Sdp	#
889daaffb31Sdp	# Now combine into a valid HTML file and side-by-side into a table
890daaffb31Sdp	#
891daaffb31Sdp	print "$HTML<head>$STDHEAD"
892cdf0c1d5Smjnelson	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
893daaffb31Sdp	print "</head><body id=\"SUNWwebrev\">"
894daaffb31Sdp        print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
895daaffb31Sdp	print "<pre>$COMMENT</pre>\n"
896daaffb31Sdp	print "<table><tr valign=\"top\">"
897daaffb31Sdp	print "<td><pre>"
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file1.html
9007c478bd9Sstevel@tonic-gate
901daaffb31Sdp	print "</pre></td><td><pre>"
9027c478bd9Sstevel@tonic-gate
9037c478bd9Sstevel@tonic-gate	strip_unchanged /tmp/$$.file2.html
9047c478bd9Sstevel@tonic-gate
905daaffb31Sdp	print "</pre></td>"
906daaffb31Sdp	print "</tr></table>"
907daaffb31Sdp	print "</body></html>"
9087c478bd9Sstevel@tonic-gate
909daaffb31Sdp	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
910daaffb31Sdp	    "$COMMENT"
9117c478bd9Sstevel@tonic-gate}
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate
914daaffb31Sdp#
915daaffb31Sdp# framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
916daaffb31Sdp#
917daaffb31Sdp# Expects lefthand and righthand side html files created by sdiff_to_html.
918daaffb31Sdp# We use insert_anchors() to augment those with HTML navigation anchors,
919daaffb31Sdp# and then emit the main frame.  Content is placed into:
920daaffb31Sdp#
921daaffb31Sdp#    $WDIR/DIR/$TNAME.lhs.html
922daaffb31Sdp#    $WDIR/DIR/$TNAME.rhs.html
923daaffb31Sdp#    $WDIR/DIR/$TNAME.frames.html
924daaffb31Sdp#
925daaffb31Sdp# NOTE: We rely on standard usage of $WDIR and $DIR.
926daaffb31Sdp#
9277c478bd9Sstevel@tonic-gatefunction framed_sdiff
9287c478bd9Sstevel@tonic-gate{
9297c478bd9Sstevel@tonic-gate	typeset TNAME=$1
930daaffb31Sdp	typeset TPATH=$2
931daaffb31Sdp	typeset lhsfile=$3
932daaffb31Sdp	typeset rhsfile=$4
933daaffb31Sdp	typeset comments=$5
9347c478bd9Sstevel@tonic-gate	typeset RTOP
935daaffb31Sdp
9367c478bd9Sstevel@tonic-gate	# Enable html files to access WDIR via a relative path.
937daaffb31Sdp	RTOP=$(relative_dir $TPATH $WDIR)
938daaffb31Sdp
939daaffb31Sdp	# Make the rhs/lhs files and output the frameset file.
940daaffb31Sdp	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
941daaffb31Sdp
942daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
9438b3b7b16SMark J. Nelson	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
9447c478bd9Sstevel@tonic-gate	    </head>
945daaffb31Sdp	    <body id="SUNWwebrev" onkeypress="keypress(event);">
946cac38512Smjnelson	    <a name="0"></a>
947cac38512Smjnelson	    <pre>$comments</pre><hr></hr>
948daaffb31Sdp	EOF
949daaffb31Sdp
950daaffb31Sdp	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
951daaffb31Sdp
952daaffb31Sdp	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
953daaffb31Sdp	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
954daaffb31Sdp
955daaffb31Sdp	close='</body></html>'
956daaffb31Sdp
957daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.lhs.html
958daaffb31Sdp	print $close >> $WDIR/$DIR/$TNAME.rhs.html
959daaffb31Sdp
960daaffb31Sdp	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
961daaffb31Sdp	print "<title>$WNAME Framed-Sdiff " \
962daaffb31Sdp	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
963daaffb31Sdp	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
964daaffb31Sdp	  <frameset rows="*,60">
965daaffb31Sdp	    <frameset cols="50%,50%">
966cac38512Smjnelson	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
967cac38512Smjnelson	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
968daaffb31Sdp	    </frameset>
9698b3b7b16SMark J. Nelson	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
970cac38512Smjnelson	   marginheight="0" name="nav"></frame>
971daaffb31Sdp	  <noframes>
972daaffb31Sdp            <body id="SUNWwebrev">
973daaffb31Sdp	      Alas 'frames' webrev requires that your browser supports frames
9747c478bd9Sstevel@tonic-gate	      and has the feature enabled.
975daaffb31Sdp            </body>
976daaffb31Sdp	  </noframes>
977daaffb31Sdp	  </frameset>
9787c478bd9Sstevel@tonic-gate	</html>
9797c478bd9Sstevel@tonic-gate	EOF
9807c478bd9Sstevel@tonic-gate}
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate
983daaffb31Sdp#
984daaffb31Sdp# fix_postscript
985daaffb31Sdp#
986daaffb31Sdp# Merge codereview output files to a single conforming postscript file, by:
987daaffb31Sdp#	- removing all extraneous headers/trailers
988daaffb31Sdp#	- making the page numbers right
989daaffb31Sdp#	- removing pages devoid of contents which confuse some
990daaffb31Sdp#	  postscript readers.
991daaffb31Sdp#
992daaffb31Sdp# From Casper.
993daaffb31Sdp#
994daaffb31Sdpfunction fix_postscript
9957c478bd9Sstevel@tonic-gate{
996daaffb31Sdp	infile=$1
9977c478bd9Sstevel@tonic-gate
998daaffb31Sdp	cat > /tmp/$$.crmerge.pl << \EOF
9997c478bd9Sstevel@tonic-gate
1000daaffb31Sdp	print scalar(<>);		# %!PS-Adobe---
1001daaffb31Sdp	print "%%Orientation: Landscape\n";
10027c478bd9Sstevel@tonic-gate
1003daaffb31Sdp	$pno = 0;
1004daaffb31Sdp	$doprint = 1;
1005daaffb31Sdp
1006daaffb31Sdp	$page = "";
1007daaffb31Sdp
1008daaffb31Sdp	while (<>) {
1009daaffb31Sdp		next if (/^%%Pages:\s*\d+/);
1010daaffb31Sdp
1011daaffb31Sdp		if (/^%%Page:/) {
1012daaffb31Sdp			if ($pno == 0 || $page =~ /\)S/) {
1013daaffb31Sdp				# Header or single page containing text
1014daaffb31Sdp				print "%%Page: ? $pno\n" if ($pno > 0);
1015daaffb31Sdp				print $page;
1016daaffb31Sdp				$pno++;
1017daaffb31Sdp			} else {
1018daaffb31Sdp				# Empty page, skip it.
10197c478bd9Sstevel@tonic-gate			}
1020daaffb31Sdp			$page = "";
1021daaffb31Sdp			$doprint = 1;
10227c478bd9Sstevel@tonic-gate			next;
10237c478bd9Sstevel@tonic-gate		}
10247c478bd9Sstevel@tonic-gate
1025daaffb31Sdp		# Skip from %%Trailer of one document to Endprolog
1026daaffb31Sdp		# %%Page of the next
1027daaffb31Sdp		$doprint = 0 if (/^%%Trailer/);
1028daaffb31Sdp		$page .= $_ if ($doprint);
10297c478bd9Sstevel@tonic-gate	}
10307c478bd9Sstevel@tonic-gate
1031daaffb31Sdp	if ($page =~ /\)S/) {
1032daaffb31Sdp		print "%%Page: ? $pno\n";
1033daaffb31Sdp		print $page;
1034daaffb31Sdp	} else {
1035daaffb31Sdp		$pno--;
1036daaffb31Sdp	}
1037daaffb31Sdp	print "%%Trailer\n%%Pages: $pno\n";
1038daaffb31SdpEOF
1039daaffb31Sdp
104014983201Sdp	$PERL /tmp/$$.crmerge.pl < $infile
1041daaffb31Sdp}
1042daaffb31Sdp
1043daaffb31Sdp
1044daaffb31Sdp#
1045daaffb31Sdp# input_cmd | insert_anchors | output_cmd
1046daaffb31Sdp#
10477c478bd9Sstevel@tonic-gate# Flag blocks of difference with sequentially numbered invisible
1048daaffb31Sdp# anchors.  These are used to drive the frames version of the
10497c478bd9Sstevel@tonic-gate# sdiffs output.
10507c478bd9Sstevel@tonic-gate#
10517c478bd9Sstevel@tonic-gate# NOTE: Anchor zero flags the top of the file irrespective of changes,
10527c478bd9Sstevel@tonic-gate# an additional anchor is also appended to flag the bottom.
10537c478bd9Sstevel@tonic-gate#
1054daaffb31Sdp# The script detects changed lines as any line that has a "<span
1055daaffb31Sdp# class=" string embedded (unchanged lines have no class set and are
1056daaffb31Sdp# not part of a <span>.  Blank lines (without a sequence number)
10577c478bd9Sstevel@tonic-gate# are also detected since they flag lines that have been inserted or
10587c478bd9Sstevel@tonic-gate# deleted.
10597c478bd9Sstevel@tonic-gate#
1060daaffb31Sdpfunction insert_anchors
1061daaffb31Sdp{
1062cdf0c1d5Smjnelson	$AWK '
10637c478bd9Sstevel@tonic-gate	function ia() {
1064daaffb31Sdp		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
10657c478bd9Sstevel@tonic-gate	}
1066daaffb31Sdp
10677c478bd9Sstevel@tonic-gate	BEGIN {
1068daaffb31Sdp		anc=1;
10697c478bd9Sstevel@tonic-gate		inblock=1;
1070daaffb31Sdp		printf "<pre>\n";
10717c478bd9Sstevel@tonic-gate	}
1072daaffb31Sdp	NF == 0 || /^<span class=/ {
10737c478bd9Sstevel@tonic-gate		if (inblock == 0) {
10747c478bd9Sstevel@tonic-gate			ia();
10757c478bd9Sstevel@tonic-gate			inblock=1;
10767c478bd9Sstevel@tonic-gate		}
10777c478bd9Sstevel@tonic-gate		print;
10787c478bd9Sstevel@tonic-gate		next;
10797c478bd9Sstevel@tonic-gate	}
10807c478bd9Sstevel@tonic-gate	{
10817c478bd9Sstevel@tonic-gate		inblock=0;
10827c478bd9Sstevel@tonic-gate		print;
10837c478bd9Sstevel@tonic-gate	}
10847c478bd9Sstevel@tonic-gate	END {
10857c478bd9Sstevel@tonic-gate		ia();
1086daaffb31Sdp
1087daaffb31Sdp		printf "<b style=\"font-size: large; color: red\">";
1088daaffb31Sdp		printf "--- EOF ---</b>"
10897c478bd9Sstevel@tonic-gate		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
1090daaffb31Sdp		printf "</pre>"
1091daaffb31Sdp		printf "<form name=\"eof\">";
1092cac38512Smjnelson		printf "<input name=\"value\" value=\"%d\" " \
1093cac38512Smjnelson		    "type=\"hidden\"></input>", anc - 1;
1094daaffb31Sdp		printf "</form>";
10957c478bd9Sstevel@tonic-gate	}
10967c478bd9Sstevel@tonic-gate	' $1
10977c478bd9Sstevel@tonic-gate}
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate
1100daaffb31Sdp#
1101daaffb31Sdp# relative_dir
1102daaffb31Sdp#
1103daaffb31Sdp# Print a relative return path from $1 to $2.  For example if
1104daaffb31Sdp# $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
1105daaffb31Sdp# this function would print "../../../../".
1106daaffb31Sdp#
1107daaffb31Sdp# In the event that $1 is not in $2 a warning is printed to stderr,
1108daaffb31Sdp# and $2 is returned-- the result of this is that the resulting webrev
1109daaffb31Sdp# is not relocatable.
1110daaffb31Sdp#
1111daaffb31Sdpfunction relative_dir
11127c478bd9Sstevel@tonic-gate{
1113daaffb31Sdp        typeset cur="${1##$2?(/)}"
11148b3b7b16SMark J. Nelson
11158b3b7b16SMark J. Nelson        #
11168b3b7b16SMark J. Nelson        # If the first path was specified absolutely, and it does
11178b3b7b16SMark J. Nelson        # not start with the second path, it's an error.
11188b3b7b16SMark J. Nelson        #
11190fd2682eSMark J. Nelson        if [[ "$cur" = "/${1#/}" ]]; then
1120daaffb31Sdp                # Should never happen.
112114983201Sdp                print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
1122daaffb31Sdp                print -u2 "to \"$2\".  Check input paths.  Framed webrev "
1123daaffb31Sdp                print -u2 "will not be relocatable!"
1124daaffb31Sdp                print $2
1125daaffb31Sdp                return
1126daaffb31Sdp        fi
1127daaffb31Sdp
11288b3b7b16SMark J. Nelson	#
11298b3b7b16SMark J. Nelson	# This is kind of ugly.  The sed script will do the following:
11308b3b7b16SMark J. Nelson	#
11318b3b7b16SMark J. Nelson	# 1. Strip off a leading "." or "./": this is important to get
11328b3b7b16SMark J. Nelson	#    the correct arcnav links for files in $WDIR.
11338b3b7b16SMark J. Nelson	# 2. Strip off a trailing "/": this is not strictly necessary,
11348b3b7b16SMark J. Nelson	#    but is kind of nice, since it doesn't end up in "//" at
11358b3b7b16SMark J. Nelson	#    the end of a relative path.
11368b3b7b16SMark J. Nelson	# 3. Replace all remaining sequences of non-"/" with "..": the
11378b3b7b16SMark J. Nelson	#    assumption here is that each dirname represents another
11388b3b7b16SMark J. Nelson	#    level of relative separation.
11398b3b7b16SMark J. Nelson	# 4. Append a trailing "/" only for non-empty paths: this way
11408b3b7b16SMark J. Nelson	#    the caller doesn't need to duplicate this logic, and does
11418b3b7b16SMark J. Nelson	#    not end up using $RTOP/file for files in $WDIR.
11428b3b7b16SMark J. Nelson	#
11430fd2682eSMark J. Nelson	print $cur | $SED -e '{
11448b3b7b16SMark J. Nelson		s:^\./*::
11458b3b7b16SMark J. Nelson		s:/$::
11468b3b7b16SMark J. Nelson		s:[^/][^/]*:..:g
11470fd2682eSMark J. Nelson		s:^\(..*\)$:\1/:
11480fd2682eSMark J. Nelson	}'
11497c478bd9Sstevel@tonic-gate}
11507c478bd9Sstevel@tonic-gate
1151daaffb31Sdp#
1152daaffb31Sdp# frame_nav_js
1153daaffb31Sdp#
1154daaffb31Sdp# Emit javascript for frame navigation
1155daaffb31Sdp#
1156daaffb31Sdpfunction frame_nav_js
11577c478bd9Sstevel@tonic-gate{
11587c478bd9Sstevel@tonic-gatecat << \EOF
11597c478bd9Sstevel@tonic-gatevar myInt;
11607c478bd9Sstevel@tonic-gatevar scrolling=0;
1161daaffb31Sdpvar sfactor = 3;
11627c478bd9Sstevel@tonic-gatevar scount=10;
11637c478bd9Sstevel@tonic-gate
11647c478bd9Sstevel@tonic-gatefunction scrollByPix() {
11657c478bd9Sstevel@tonic-gate	if (scount<=0) {
11667c478bd9Sstevel@tonic-gate		sfactor*=1.2;
11677c478bd9Sstevel@tonic-gate		scount=10;
11687c478bd9Sstevel@tonic-gate	}
11697c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,sfactor);
11707c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,sfactor);
11717c478bd9Sstevel@tonic-gate	scount--;
11727c478bd9Sstevel@tonic-gate}
11737c478bd9Sstevel@tonic-gate
1174daaffb31Sdpfunction scrollToAnc(num) {
1175daaffb31Sdp
1176daaffb31Sdp	// Update the value of the anchor in the form which we use as
1177daaffb31Sdp	// storage for this value.  setAncValue() will take care of
1178daaffb31Sdp	// correcting for overflow and underflow of the value and return
1179daaffb31Sdp	// us the new value.
1180daaffb31Sdp	num = setAncValue(num);
1181daaffb31Sdp
1182daaffb31Sdp	// Set location and scroll back a little to expose previous
1183daaffb31Sdp	// lines.
1184daaffb31Sdp	//
1185daaffb31Sdp	// Note that this could be improved: it is possible although
1186daaffb31Sdp	// complex to compute the x and y position of an anchor, and to
1187daaffb31Sdp	// scroll to that location directly.
1188daaffb31Sdp	//
11897c478bd9Sstevel@tonic-gate	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
11907c478bd9Sstevel@tonic-gate	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
1191daaffb31Sdp
11927c478bd9Sstevel@tonic-gate	parent.lhs.scrollBy(0,-30);
11937c478bd9Sstevel@tonic-gate	parent.rhs.scrollBy(0,-30);
11947c478bd9Sstevel@tonic-gate}
11957c478bd9Sstevel@tonic-gate
1196daaffb31Sdpfunction getAncValue()
1197daaffb31Sdp{
1198daaffb31Sdp	return (parseInt(parent.nav.document.diff.real.value));
1199daaffb31Sdp}
1200daaffb31Sdp
1201daaffb31Sdpfunction setAncValue(val)
1202daaffb31Sdp{
1203daaffb31Sdp	if (val <= 0) {
1204daaffb31Sdp		val = 0;
1205daaffb31Sdp		parent.nav.document.diff.real.value = val;
1206daaffb31Sdp		parent.nav.document.diff.display.value = "BOF";
1207daaffb31Sdp		return (val);
1208daaffb31Sdp	}
1209daaffb31Sdp
1210daaffb31Sdp	//
1211daaffb31Sdp	// The way we compute the max anchor value is to stash it
1212daaffb31Sdp	// inline in the left and right hand side pages-- it's the same
1213daaffb31Sdp	// on each side, so we pluck from the left.
1214daaffb31Sdp	//
1215daaffb31Sdp	maxval = parent.lhs.document.eof.value.value;
1216daaffb31Sdp	if (val < maxval) {
1217daaffb31Sdp		parent.nav.document.diff.real.value = val;
1218daaffb31Sdp		parent.nav.document.diff.display.value = val.toString();
1219daaffb31Sdp		return (val);
1220daaffb31Sdp	}
1221daaffb31Sdp
1222daaffb31Sdp	// this must be: val >= maxval
1223daaffb31Sdp	val = maxval;
1224daaffb31Sdp	parent.nav.document.diff.real.value = val;
1225daaffb31Sdp	parent.nav.document.diff.display.value = "EOF";
1226daaffb31Sdp	return (val);
1227daaffb31Sdp}
1228daaffb31Sdp
12297c478bd9Sstevel@tonic-gatefunction stopScroll() {
12307c478bd9Sstevel@tonic-gate	if (scrolling==1) {
12317c478bd9Sstevel@tonic-gate		clearInterval(myInt);
12327c478bd9Sstevel@tonic-gate		scrolling=0;
12337c478bd9Sstevel@tonic-gate	}
12347c478bd9Sstevel@tonic-gate}
12357c478bd9Sstevel@tonic-gate
12367c478bd9Sstevel@tonic-gatefunction startScroll() {
12377c478bd9Sstevel@tonic-gate	stopScroll();
12387c478bd9Sstevel@tonic-gate	scrolling=1;
12397c478bd9Sstevel@tonic-gate	myInt=setInterval("scrollByPix()",10);
12407c478bd9Sstevel@tonic-gate}
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gatefunction handlePress(b) {
1243daaffb31Sdp
12447c478bd9Sstevel@tonic-gate	switch (b) {
12457c478bd9Sstevel@tonic-gate	    case 1 :
1246daaffb31Sdp		scrollToAnc(-1);
12477c478bd9Sstevel@tonic-gate		break;
12487c478bd9Sstevel@tonic-gate	    case 2 :
1249daaffb31Sdp		scrollToAnc(getAncValue() - 1);
12507c478bd9Sstevel@tonic-gate		break;
12517c478bd9Sstevel@tonic-gate	    case 3 :
12527c478bd9Sstevel@tonic-gate		sfactor=-3;
12537c478bd9Sstevel@tonic-gate		startScroll();
12547c478bd9Sstevel@tonic-gate		break;
12557c478bd9Sstevel@tonic-gate	    case 4 :
12567c478bd9Sstevel@tonic-gate		sfactor=3;
12577c478bd9Sstevel@tonic-gate		startScroll();
12587c478bd9Sstevel@tonic-gate		break;
12597c478bd9Sstevel@tonic-gate	    case 5 :
1260daaffb31Sdp		scrollToAnc(getAncValue() + 1);
12617c478bd9Sstevel@tonic-gate		break;
12627c478bd9Sstevel@tonic-gate	    case 6 :
1263daaffb31Sdp		scrollToAnc(999999);
12647c478bd9Sstevel@tonic-gate		break;
12657c478bd9Sstevel@tonic-gate	}
12667c478bd9Sstevel@tonic-gate}
12677c478bd9Sstevel@tonic-gate
12687c478bd9Sstevel@tonic-gatefunction handleRelease(b) {
12697c478bd9Sstevel@tonic-gate	stopScroll();
12707c478bd9Sstevel@tonic-gate}
12717c478bd9Sstevel@tonic-gate
1272daaffb31Sdpfunction keypress(ev) {
1273daaffb31Sdp	var keynum;
1274daaffb31Sdp	var keychar;
1275daaffb31Sdp
1276daaffb31Sdp	if (window.event) { // IE
1277daaffb31Sdp		keynum = ev.keyCode;
1278daaffb31Sdp	} else if (ev.which) { // non-IE
1279daaffb31Sdp		keynum = ev.which;
1280daaffb31Sdp	}
1281daaffb31Sdp
1282daaffb31Sdp	keychar = String.fromCharCode(keynum);
1283daaffb31Sdp
1284daaffb31Sdp	if (keychar == "k") {
1285daaffb31Sdp		handlePress(2);
1286daaffb31Sdp		return (0);
1287daaffb31Sdp	} else if (keychar == "j" || keychar == " ") {
1288daaffb31Sdp		handlePress(5);
1289daaffb31Sdp		return (0);
1290daaffb31Sdp	}
1291daaffb31Sdp	return (1);
1292daaffb31Sdp}
1293daaffb31Sdp
12947c478bd9Sstevel@tonic-gatefunction ValidateDiffNum(){
1295daaffb31Sdp	val = parent.nav.document.diff.display.value;
1296daaffb31Sdp	if (val == "EOF") {
1297daaffb31Sdp		scrollToAnc(999999);
1298daaffb31Sdp		return;
1299daaffb31Sdp	}
1300daaffb31Sdp
1301daaffb31Sdp	if (val == "BOF") {
1302daaffb31Sdp		scrollToAnc(0);
1303daaffb31Sdp		return;
1304daaffb31Sdp	}
1305daaffb31Sdp
1306daaffb31Sdp        i=parseInt(val);
13077c478bd9Sstevel@tonic-gate        if (isNaN(i)) {
1308daaffb31Sdp                parent.nav.document.diff.display.value = getAncValue();
13097c478bd9Sstevel@tonic-gate        } else {
1310daaffb31Sdp                scrollToAnc(i);
13117c478bd9Sstevel@tonic-gate        }
13127c478bd9Sstevel@tonic-gate        return false;
13137c478bd9Sstevel@tonic-gate}
13147c478bd9Sstevel@tonic-gate
1315daaffb31SdpEOF
1316daaffb31Sdp}
1317daaffb31Sdp
1318daaffb31Sdp#
1319daaffb31Sdp# frame_navigation
1320daaffb31Sdp#
1321daaffb31Sdp# Output anchor navigation file for framed sdiffs.
1322daaffb31Sdp#
1323daaffb31Sdpfunction frame_navigation
1324daaffb31Sdp{
1325daaffb31Sdp	print "$HTML<head>$STDHEAD"
1326daaffb31Sdp
1327daaffb31Sdp	cat << \EOF
1328daaffb31Sdp<title>Anchor Navigation</title>
1329daaffb31Sdp<meta http-equiv="Content-Script-Type" content="text/javascript">
1330daaffb31Sdp<meta http-equiv="Content-Type" content="text/html">
1331daaffb31Sdp
1332daaffb31Sdp<style type="text/css">
1333daaffb31Sdp    div.button td { padding-left: 5px; padding-right: 5px;
1334daaffb31Sdp		    background-color: #eee; text-align: center;
1335daaffb31Sdp		    border: 1px #444 outset; cursor: pointer; }
1336daaffb31Sdp    div.button a { font-weight: bold; color: black }
1337daaffb31Sdp    div.button td:hover { background: #ffcc99; }
1338daaffb31Sdp</style>
1339daaffb31SdpEOF
1340daaffb31Sdp
1341cac38512Smjnelson	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
1342daaffb31Sdp
1343daaffb31Sdp	cat << \EOF
13447c478bd9Sstevel@tonic-gate</head>
1345daaffb31Sdp<body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
1346daaffb31Sdp	onkeypress="keypress(event);">
13477c478bd9Sstevel@tonic-gate    <noscript lang="javascript">
13487c478bd9Sstevel@tonic-gate      <center>
1349cac38512Smjnelson	<p><big>Framed Navigation controls require Javascript</big><br></br>
13507c478bd9Sstevel@tonic-gate	Either this browser is incompatable or javascript is not enabled</p>
13517c478bd9Sstevel@tonic-gate      </center>
13527c478bd9Sstevel@tonic-gate    </noscript>
13537c478bd9Sstevel@tonic-gate    <table width="100%" border="0" align="center">
1354daaffb31Sdp	<tr>
1355daaffb31Sdp          <td valign="middle" width="25%">Diff navigation:
1356daaffb31Sdp          Use 'j' and 'k' for next and previous diffs; or use buttons
1357daaffb31Sdp          at right</td>
1358daaffb31Sdp	  <td align="center" valign="top" width="50%">
13597c478bd9Sstevel@tonic-gate	    <div class="button">
1360daaffb31Sdp	      <table border="0" align="center">
1361daaffb31Sdp                  <tr>
1362daaffb31Sdp		    <td>
13637c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(1);return true;"
13647c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(1);return true;"
13657c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(1);return true;"
13667c478bd9Sstevel@tonic-gate			 onClick="return false;"
13677c478bd9Sstevel@tonic-gate			 title="Go to Beginning Of file">BOF</a></td>
1368daaffb31Sdp		    <td>
13697c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(3);return true;"
13707c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(3);return true;"
13717c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(3);return true;"
13727c478bd9Sstevel@tonic-gate			 title="Scroll Up: Press and Hold to accelerate"
1373daaffb31Sdp			 onClick="return false;">Scroll Up</a></td>
1374daaffb31Sdp		    <td>
13757c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(2);return true;"
13767c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(2);return true;"
13777c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(2);return true;"
13787c478bd9Sstevel@tonic-gate			 title="Go to previous Diff"
13797c478bd9Sstevel@tonic-gate			 onClick="return false;">Prev Diff</a>
13807c478bd9Sstevel@tonic-gate		    </td></tr>
1381daaffb31Sdp
13827c478bd9Sstevel@tonic-gate		  <tr>
1383daaffb31Sdp		    <td>
13847c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(6);return true;"
13857c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(6);return true;"
13867c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(6);return true;"
13877c478bd9Sstevel@tonic-gate			 onClick="return false;"
13887c478bd9Sstevel@tonic-gate			 title="Go to End Of File">EOF</a></td>
1389daaffb31Sdp		    <td>
13907c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(4);return true;"
13917c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(4);return true;"
13927c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(4);return true;"
13937c478bd9Sstevel@tonic-gate			 title="Scroll Down: Press and Hold to accelerate"
1394daaffb31Sdp			 onClick="return false;">Scroll Down</a></td>
1395daaffb31Sdp		    <td>
13967c478bd9Sstevel@tonic-gate		      <a onMouseDown="handlePress(5);return true;"
13977c478bd9Sstevel@tonic-gate			 onMouseUp="handleRelease(5);return true;"
13987c478bd9Sstevel@tonic-gate			 onMouseOut="handleRelease(5);return true;"
13997c478bd9Sstevel@tonic-gate			 title="Go to next Diff"
14007c478bd9Sstevel@tonic-gate			 onClick="return false;">Next Diff</a></td>
1401daaffb31Sdp		  </tr>
1402daaffb31Sdp              </table>
1403daaffb31Sdp	    </div>
1404daaffb31Sdp	  </td>
14057c478bd9Sstevel@tonic-gate	  <th valign="middle" width="25%">
1406daaffb31Sdp	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
1407cac38512Smjnelson		<input name="display" value="BOF" size="8" type="text"></input>
1408cac38512Smjnelson		<input name="real" value="0" size="8" type="hidden"></input>
14097c478bd9Sstevel@tonic-gate	    </form>
14107c478bd9Sstevel@tonic-gate	  </th>
1411daaffb31Sdp	</tr>
14127c478bd9Sstevel@tonic-gate    </table>
14137c478bd9Sstevel@tonic-gate  </body>
14147c478bd9Sstevel@tonic-gate</html>
14157c478bd9Sstevel@tonic-gateEOF
14167c478bd9Sstevel@tonic-gate}
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate
1419daaffb31Sdp
1420daaffb31Sdp#
1421daaffb31Sdp# diff_to_html <filename> <filepath> { U | C } <comment>
1422daaffb31Sdp#
1423daaffb31Sdp# Processes the output of diff to produce an HTML file representing either
1424daaffb31Sdp# context or unified diffs.
1425daaffb31Sdp#
14267c478bd9Sstevel@tonic-gatediff_to_html()
14277c478bd9Sstevel@tonic-gate{
14287c478bd9Sstevel@tonic-gate	TNAME=$1
1429daaffb31Sdp	TPATH=$2
1430daaffb31Sdp	DIFFTYPE=$3
1431daaffb31Sdp	COMMENT=$4
1432daaffb31Sdp
1433daaffb31Sdp	print "$HTML<head>$STDHEAD"
1434daaffb31Sdp	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
1435daaffb31Sdp
1436daaffb31Sdp	if [[ $DIFFTYPE == "U" ]]; then
1437daaffb31Sdp		print "$UDIFFCSS"
1438daaffb31Sdp	fi
1439daaffb31Sdp
1440daaffb31Sdp	cat <<-EOF
1441daaffb31Sdp	</head>
1442daaffb31Sdp	<body id="SUNWwebrev">
1443daaffb31Sdp        <a class="print" href="javascript:print()">Print this page</a>
1444daaffb31Sdp	<pre>$COMMENT</pre>
1445daaffb31Sdp        <pre>
1446daaffb31Sdp	EOF
14477c478bd9Sstevel@tonic-gate
1448cdf0c1d5Smjnelson	html_quote | $AWK '
1449daaffb31Sdp	/^--- new/	{ next }
1450daaffb31Sdp	/^\+\+\+ new/	{ next }
1451daaffb31Sdp	/^--- old/	{ next }
1452daaffb31Sdp	/^\*\*\* old/	{ next }
1453daaffb31Sdp	/^\*\*\*\*/	{ next }
14547c478bd9Sstevel@tonic-gate	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
1455cac38512Smjnelson	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
1456daaffb31Sdp			  printf "<span class=\"newmarker\">%s</span>\n", $0;
1457daaffb31Sdp			  next}
1458daaffb31Sdp
1459cac38512Smjnelson	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
1460daaffb31Sdp			  next}
1461daaffb31Sdp	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
1462daaffb31Sdp			  next}
1463daaffb31Sdp	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
1464daaffb31Sdp	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
1465daaffb31Sdp	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
1466daaffb31Sdp			{printf "%s\n", $0; next}
14677c478bd9Sstevel@tonic-gate	'
1468daaffb31Sdp
1469daaffb31Sdp	print "</pre></body></html>\n"
14707c478bd9Sstevel@tonic-gate}
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate
1473daaffb31Sdp#
1474daaffb31Sdp# source_to_html { new | old } <filename>
1475daaffb31Sdp#
1476daaffb31Sdp# Process a plain vanilla source file to transform it into an HTML file.
1477daaffb31Sdp#
14787c478bd9Sstevel@tonic-gatesource_to_html()
14797c478bd9Sstevel@tonic-gate{
14807c478bd9Sstevel@tonic-gate	WHICH=$1
14817c478bd9Sstevel@tonic-gate	TNAME=$2
14827c478bd9Sstevel@tonic-gate
1483daaffb31Sdp	print "$HTML<head>$STDHEAD"
1484cdf0c1d5Smjnelson	print "<title>$WNAME $WHICH $TNAME</title>"
1485daaffb31Sdp	print "<body id=\"SUNWwebrev\">"
1486daaffb31Sdp	print "<pre>"
1487cdf0c1d5Smjnelson	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
1488daaffb31Sdp	print "</pre></body></html>"
14897c478bd9Sstevel@tonic-gate}
14907c478bd9Sstevel@tonic-gate
1491daaffb31Sdp#
1492cdf0c1d5Smjnelson# comments_from_wx {text|html} filepath
1493daaffb31Sdp#
1494cdf0c1d5Smjnelson# Given the pathname of a file, find its location in a "wx" active
1495cdf0c1d5Smjnelson# file list and print the following comment.  Output is either text or
1496cdf0c1d5Smjnelson# HTML; if the latter, embedded bugids (sequence of 5 or more digits)
1497cdf0c1d5Smjnelson# are turned into URLs.
1498cdf0c1d5Smjnelson#
1499cdf0c1d5Smjnelson# This is also used with Mercurial and the file list provided by hg-active.
1500daaffb31Sdp#
1501daaffb31Sdpcomments_from_wx()
15027c478bd9Sstevel@tonic-gate{
1503daaffb31Sdp	typeset fmt=$1
1504daaffb31Sdp	typeset p=$2
15057c478bd9Sstevel@tonic-gate
1506cdf0c1d5Smjnelson	comm=`$AWK '
1507daaffb31Sdp	$1 == "'$p'" {
15087c478bd9Sstevel@tonic-gate		do getline ; while (NF > 0)
15097c478bd9Sstevel@tonic-gate		getline
15107c478bd9Sstevel@tonic-gate		while (NF > 0) { print ; getline }
15117c478bd9Sstevel@tonic-gate		exit
1512daaffb31Sdp	}' < $wxfile`
1513daaffb31Sdp
1514cdf0c1d5Smjnelson	if [[ -z $comm ]]; then
1515cdf0c1d5Smjnelson		comm="*** NO COMMENTS ***"
1516cdf0c1d5Smjnelson	fi
1517cdf0c1d5Smjnelson
1518daaffb31Sdp	if [[ $fmt == "text" ]]; then
1519cdf0c1d5Smjnelson		print -- "$comm"
1520daaffb31Sdp		return
1521daaffb31Sdp	fi
1522daaffb31Sdp
15230fd2682eSMark J. Nelson	print -- "$comm" | html_quote | its2url
1524cdf0c1d5Smjnelson
15257c478bd9Sstevel@tonic-gate}
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate#
1528daaffb31Sdp# getcomments {text|html} filepath parentpath
1529daaffb31Sdp#
1530daaffb31Sdp# Fetch the comments depending on what SCM mode we're in.
1531daaffb31Sdp#
1532daaffb31Sdpgetcomments()
1533daaffb31Sdp{
1534daaffb31Sdp	typeset fmt=$1
1535daaffb31Sdp	typeset p=$2
1536daaffb31Sdp	typeset pp=$3
15377c478bd9Sstevel@tonic-gate
15383df69ef3SDarren Moffat	if [[ -n $Nflag ]]; then
15393df69ef3SDarren Moffat		return
15403df69ef3SDarren Moffat	fi
1541cdf0c1d5Smjnelson	#
1542cdf0c1d5Smjnelson	# Mercurial support uses a file list in wx format, so this
1543cdf0c1d5Smjnelson	# will be used there, too
1544cdf0c1d5Smjnelson	#
1545daaffb31Sdp	if [[ -n $wxfile ]]; then
1546daaffb31Sdp		comments_from_wx $fmt $p
1547daaffb31Sdp	fi
1548daaffb31Sdp}
1549daaffb31Sdp
1550daaffb31Sdp#
1551daaffb31Sdp# printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
1552daaffb31Sdp#
1553daaffb31Sdp# Print out Code Inspection figures similar to sccs-prt(1) format.
1554daaffb31Sdp#
1555daaffb31Sdpfunction printCI
1556daaffb31Sdp{
1557daaffb31Sdp	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
1558daaffb31Sdp	typeset str
1559daaffb31Sdp	if (( tot == 1 )); then
1560daaffb31Sdp		str="line"
1561daaffb31Sdp	else
1562daaffb31Sdp		str="lines"
1563daaffb31Sdp	fi
1564daaffb31Sdp	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
1565daaffb31Sdp	    $tot $str $ins $del $mod $unc
1566daaffb31Sdp}
1567daaffb31Sdp
1568daaffb31Sdp
1569daaffb31Sdp#
1570daaffb31Sdp# difflines <oldfile> <newfile>
1571daaffb31Sdp#
1572daaffb31Sdp# Calculate and emit number of added, removed, modified and unchanged lines,
1573daaffb31Sdp# and total lines changed, the sum of added + removed + modified.
1574daaffb31Sdp#
15757c478bd9Sstevel@tonic-gatefunction difflines
15767c478bd9Sstevel@tonic-gate{
1577daaffb31Sdp	integer tot mod del ins unc err
15787c478bd9Sstevel@tonic-gate	typeset filename
15797c478bd9Sstevel@tonic-gate
1580cdf0c1d5Smjnelson	eval $( diff -e $1 $2 | $AWK '
1581daaffb31Sdp	# Change range of lines: N,Nc
15827c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*c$/ {
15837c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
15847c478bd9Sstevel@tonic-gate		if (n != 2) {
15857c478bd9Sstevel@tonic-gate		    error=2
15867c478bd9Sstevel@tonic-gate		    exit;
15877c478bd9Sstevel@tonic-gate		}
1588daaffb31Sdp		#
1589daaffb31Sdp		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1590daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1591daaffb31Sdp		#
15927c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
1593daaffb31Sdp
1594daaffb31Sdp		#
1595daaffb31Sdp		# Now count replacement lines: each represents a change instead
1596daaffb31Sdp		# of a delete, so increment c and decrement r.
1597daaffb31Sdp		#
15987c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) {
15997c478bd9Sstevel@tonic-gate			c++;
16007c478bd9Sstevel@tonic-gate			r--;
16017c478bd9Sstevel@tonic-gate		}
1602daaffb31Sdp		#
1603daaffb31Sdp		# If there were more replacement lines than original lines,
1604daaffb31Sdp		# then r will be negative; in this case there are no deletions,
1605daaffb31Sdp		# but there are r changes that should be counted as adds, and
1606daaffb31Sdp		# since r is negative, subtract it from a and add it to c.
1607daaffb31Sdp		#
16087c478bd9Sstevel@tonic-gate		if (r < 0) {
16097c478bd9Sstevel@tonic-gate			a-=r;
16107c478bd9Sstevel@tonic-gate			c+=r;
16117c478bd9Sstevel@tonic-gate		}
1612daaffb31Sdp
1613daaffb31Sdp		#
1614daaffb31Sdp		# If there were more original lines than replacement lines, then
1615daaffb31Sdp		# r will be positive; in this case, increment d by that much.
1616daaffb31Sdp		#
16177c478bd9Sstevel@tonic-gate		if (r > 0) {
16187c478bd9Sstevel@tonic-gate			d+=r;
16197c478bd9Sstevel@tonic-gate		}
16207c478bd9Sstevel@tonic-gate		next;
16217c478bd9Sstevel@tonic-gate	}
16227c478bd9Sstevel@tonic-gate
1623daaffb31Sdp	# Change lines: Nc
16247c478bd9Sstevel@tonic-gate	/^[0-9].*c$/ {
1625daaffb31Sdp		# The first line is a replacement; any more are additions.
16267c478bd9Sstevel@tonic-gate		if (getline != /^\.$/) {
16277c478bd9Sstevel@tonic-gate			c++;
16287c478bd9Sstevel@tonic-gate			while (getline != /^\.$/) a++;
16297c478bd9Sstevel@tonic-gate		}
16307c478bd9Sstevel@tonic-gate		next;
16317c478bd9Sstevel@tonic-gate	}
16327c478bd9Sstevel@tonic-gate
1633daaffb31Sdp	# Add lines: both Na and N,Na
16347c478bd9Sstevel@tonic-gate	/^[0-9].*a$/ {
16357c478bd9Sstevel@tonic-gate		while (getline != /^\.$/) a++;
16367c478bd9Sstevel@tonic-gate		next;
16377c478bd9Sstevel@tonic-gate	}
16387c478bd9Sstevel@tonic-gate
1639daaffb31Sdp	# Delete range of lines: N,Nd
16407c478bd9Sstevel@tonic-gate	/^[0-9]*,[0-9]*d$/ {
16417c478bd9Sstevel@tonic-gate		n=split(substr($1,1,length($1)-1), counts, ",");
16427c478bd9Sstevel@tonic-gate		if (n != 2) {
16437c478bd9Sstevel@tonic-gate			error=2
16447c478bd9Sstevel@tonic-gate			exit;
16457c478bd9Sstevel@tonic-gate		}
1646daaffb31Sdp		#
1647daaffb31Sdp		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1648daaffb31Sdp		# following would be 5 - 3 = 2! Hence +1 for correction.
1649daaffb31Sdp		#
16507c478bd9Sstevel@tonic-gate		r=(counts[2]-counts[1])+1;
16517c478bd9Sstevel@tonic-gate		d+=r;
16527c478bd9Sstevel@tonic-gate		next;
16537c478bd9Sstevel@tonic-gate	}
16547c478bd9Sstevel@tonic-gate
1655daaffb31Sdp	# Delete line: Nd.   For example 10d says line 10 is deleted.
16567c478bd9Sstevel@tonic-gate	/^[0-9]*d$/ {d++; next}
16577c478bd9Sstevel@tonic-gate
1658daaffb31Sdp	# Should not get here!
16597c478bd9Sstevel@tonic-gate	{
16607c478bd9Sstevel@tonic-gate		error=1;
16617c478bd9Sstevel@tonic-gate		exit;
16627c478bd9Sstevel@tonic-gate	}
16637c478bd9Sstevel@tonic-gate
1664daaffb31Sdp	# Finish off - print results
16657c478bd9Sstevel@tonic-gate	END {
1666daaffb31Sdp		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
16677c478bd9Sstevel@tonic-gate		    (c+d+a), c, d, a, error);
16687c478bd9Sstevel@tonic-gate	}' )
16697c478bd9Sstevel@tonic-gate
1670cdf0c1d5Smjnelson	# End of $AWK, Check to see if any trouble occurred.
16717c478bd9Sstevel@tonic-gate	if (( $? > 0 || err > 0 )); then
1672daaffb31Sdp		print "Unexpected Error occurred reading" \
1673daaffb31Sdp		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
1674daaffb31Sdp		return
1675daaffb31Sdp	fi
1676daaffb31Sdp
16777c478bd9Sstevel@tonic-gate	# Accumulate totals
16787c478bd9Sstevel@tonic-gate	(( TOTL += tot ))
1679daaffb31Sdp	(( TMOD += mod ))
16807c478bd9Sstevel@tonic-gate	(( TDEL += del ))
16817c478bd9Sstevel@tonic-gate	(( TINS += ins ))
16827c478bd9Sstevel@tonic-gate	# Calculate unchanged lines
1683cdf0c1d5Smjnelson	unc=`wc -l < $1`
16847c478bd9Sstevel@tonic-gate	if (( unc > 0 )); then
1685daaffb31Sdp		(( unc -= del + mod ))
16867c478bd9Sstevel@tonic-gate		(( TUNC += unc ))
16877c478bd9Sstevel@tonic-gate	fi
16887c478bd9Sstevel@tonic-gate	# print summary
1689daaffb31Sdp	print "<span class=\"lineschanged\">"
1690daaffb31Sdp	printCI $tot $ins $del $mod $unc
1691daaffb31Sdp	print "</span>"
16927c478bd9Sstevel@tonic-gate}
16937c478bd9Sstevel@tonic-gate
1694daaffb31Sdp
16957c478bd9Sstevel@tonic-gate#
1696daaffb31Sdp# flist_from_wx
1697daaffb31Sdp#
1698daaffb31Sdp# Sets up webrev to source its information from a wx-formatted file.
1699daaffb31Sdp# Sets the global 'wxfile' variable.
1700daaffb31Sdp#
1701daaffb31Sdpfunction flist_from_wx
17027c478bd9Sstevel@tonic-gate{
1703daaffb31Sdp	typeset argfile=$1
1704daaffb31Sdp	if [[ -n ${argfile%%/*} ]]; then
1705daaffb31Sdp		#
1706daaffb31Sdp		# If the wx file pathname is relative then make it absolute
1707daaffb31Sdp		# because the webrev does a "cd" later on.
1708daaffb31Sdp		#
1709daaffb31Sdp		wxfile=$PWD/$argfile
17107c478bd9Sstevel@tonic-gate	else
1711daaffb31Sdp		wxfile=$argfile
17127c478bd9Sstevel@tonic-gate	fi
17137c478bd9Sstevel@tonic-gate
1714cdf0c1d5Smjnelson	$AWK '{ c = 1; print;
17157c478bd9Sstevel@tonic-gate	  while (getline) {
17167c478bd9Sstevel@tonic-gate		if (NF == 0) { c = -c; continue }
17177c478bd9Sstevel@tonic-gate		if (c > 0) print
17187c478bd9Sstevel@tonic-gate	  }
1719daaffb31Sdp	}' $wxfile > $FLIST
17207c478bd9Sstevel@tonic-gate
1721daaffb31Sdp	print " Done."
1722daaffb31Sdp}
17237c478bd9Sstevel@tonic-gate
1724daaffb31Sdp#
1725cdf0c1d5Smjnelson# Call hg-active to get the active list output in the wx active list format
1726cdf0c1d5Smjnelson#
1727cdf0c1d5Smjnelsonfunction hg_active_wxfile
1728cdf0c1d5Smjnelson{
1729cdf0c1d5Smjnelson	typeset child=$1
1730cdf0c1d5Smjnelson	typeset parent=$2
1731cdf0c1d5Smjnelson
1732cdf0c1d5Smjnelson	TMPFLIST=/tmp/$$.active
17339a70fc3bSMark J. Nelson	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
1734cdf0c1d5Smjnelson	wxfile=$TMPFLIST
1735cdf0c1d5Smjnelson}
1736cdf0c1d5Smjnelson
1737cdf0c1d5Smjnelson#
1738cdf0c1d5Smjnelson# flist_from_mercurial
1739cdf0c1d5Smjnelson# Call hg-active to get a wx-style active list, and hand it off to
1740cdf0c1d5Smjnelson# flist_from_wx
1741cdf0c1d5Smjnelson#
1742cdf0c1d5Smjnelsonfunction flist_from_mercurial
1743cdf0c1d5Smjnelson{
1744cdf0c1d5Smjnelson	typeset child=$1
1745cdf0c1d5Smjnelson	typeset parent=$2
1746cdf0c1d5Smjnelson
1747cdf0c1d5Smjnelson	print " File list from: hg-active -p $parent ...\c"
1748cdf0c1d5Smjnelson	if [[ ! -x $HG_ACTIVE ]]; then
1749cdf0c1d5Smjnelson		print		# Blank line for the \c above
1750cdf0c1d5Smjnelson		print -u2 "Error: hg-active tool not found.  Exiting"
1751cdf0c1d5Smjnelson		exit 1
1752cdf0c1d5Smjnelson	fi
1753cdf0c1d5Smjnelson	hg_active_wxfile $child $parent
1754cdf0c1d5Smjnelson
1755cdf0c1d5Smjnelson	# flist_from_wx prints the Done, so we don't have to.
1756cdf0c1d5Smjnelson	flist_from_wx $TMPFLIST
1757cdf0c1d5Smjnelson}
1758cdf0c1d5Smjnelson
1759cdf0c1d5Smjnelson#
17608bcea973SRichard Lowe# Transform a specified 'git log' output format into a wx-like active list.
17618bcea973SRichard Lowe#
17628bcea973SRichard Lowefunction git_wxfile
17638bcea973SRichard Lowe{
17648bcea973SRichard Lowe	typeset child="$1"
17658bcea973SRichard Lowe	typeset parent="$2"
17668bcea973SRichard Lowe
17678bcea973SRichard Lowe	TMPFLIST=/tmp/$$.active
17688bcea973SRichard Lowe	$PERL -e 'my (%files, %realfiles, $msg);
17698bcea973SRichard Lowe	my $branch = $ARGV[0];
17708bcea973SRichard Lowe
17718bcea973SRichard Lowe	open(F, "git diff -M --name-status $branch |");
17728bcea973SRichard Lowe	while (<F>) {
17738bcea973SRichard Lowe	    chomp;
17748bcea973SRichard Lowe	    if (/^R(\d+)\s+([^ ]+)\s+([^ ]+)/) { # rename
17758bcea973SRichard Lowe		if ($1 >= 75) {			 # Probably worth treating as a rename
17763cb02613SRichard Lowe		    $realfiles{$3} = $2;
17778bcea973SRichard Lowe		} else {
17788bcea973SRichard Lowe		    $realfiles{$3} = $3;
17798bcea973SRichard Lowe		    $realfiles{$2} = $2;
17808bcea973SRichard Lowe	        }
17818bcea973SRichard Lowe	    } else {
17828bcea973SRichard Lowe		my $f = (split /\s+/, $_)[1];
17838bcea973SRichard Lowe		$realfiles{$f} = $f;
17848bcea973SRichard Lowe	    }
17858bcea973SRichard Lowe	}
17868bcea973SRichard Lowe	close(F);
17878bcea973SRichard Lowe
17888bcea973SRichard Lowe	my $state = 1;		    # 0|comments, 1|files
17898bcea973SRichard Lowe	open(F, "git whatchanged --pretty=format:%B $branch.. |");
17908bcea973SRichard Lowe	while (<F>) {
17918bcea973SRichard Lowe	    chomp;
17928bcea973SRichard Lowe	    if (/^:[0-9]{6}/) {
17938bcea973SRichard Lowe		my $fname = (split /\t/, $_)[1];
17948bcea973SRichard Lowe		next if !defined($realfiles{$fname}); # No real change
17958bcea973SRichard Lowe		$state = 1;
17963cb02613SRichard Lowe		chomp $msg;
17973cb02613SRichard Lowe		$files{$fname} .= $msg;
17988bcea973SRichard Lowe	    } else {
17998bcea973SRichard Lowe		if ($state == 1) {
18008bcea973SRichard Lowe		    $state = 0;
18018bcea973SRichard Lowe		    $msg = /^\n/ ? "" : "\n";
18028bcea973SRichard Lowe		}
18038bcea973SRichard Lowe		$msg .= "$_\n" if ($_);
18048bcea973SRichard Lowe	    }
18058bcea973SRichard Lowe	}
18068bcea973SRichard Lowe	close(F);
18078bcea973SRichard Lowe
18088bcea973SRichard Lowe	for (sort keys %files) {
18098bcea973SRichard Lowe	    if ($realfiles{$_} ne $_) {
18103cb02613SRichard Lowe		print "$_ $realfiles{$_}\n$files{$_}\n\n";
18118bcea973SRichard Lowe	    } else {
18123cb02613SRichard Lowe		print "$_\n$files{$_}\n\n"
18138bcea973SRichard Lowe	    }
18148bcea973SRichard Lowe	}' ${parent} > $TMPFLIST
18158bcea973SRichard Lowe
18168bcea973SRichard Lowe	wxfile=$TMPFLIST
18178bcea973SRichard Lowe}
18188bcea973SRichard Lowe
18198bcea973SRichard Lowe#
18208bcea973SRichard Lowe# flist_from_git
18218bcea973SRichard Lowe# Build a wx-style active list, and hand it off to flist_from_wx
18228bcea973SRichard Lowe#
18238bcea973SRichard Lowefunction flist_from_git
18248bcea973SRichard Lowe{
18258bcea973SRichard Lowe	typeset child=$1
18268bcea973SRichard Lowe	typeset parent=$2
18278bcea973SRichard Lowe
18288bcea973SRichard Lowe	print " File list from: git ...\c"
18298bcea973SRichard Lowe	git_wxfile "$child" "$parent";
18308bcea973SRichard Lowe
18318bcea973SRichard Lowe	# flist_from_wx prints the Done, so we don't have to.
18328bcea973SRichard Lowe	flist_from_wx $TMPFLIST
18338bcea973SRichard Lowe}
18348bcea973SRichard Lowe
18358bcea973SRichard Lowe#
1836cdf0c1d5Smjnelson# flist_from_subversion
1837cdf0c1d5Smjnelson#
1838cdf0c1d5Smjnelson# Generate the file list by extracting file names from svn status.
1839cdf0c1d5Smjnelson#
1840cdf0c1d5Smjnelsonfunction flist_from_subversion
1841cdf0c1d5Smjnelson{
1842cdf0c1d5Smjnelson	CWS=$1
1843cdf0c1d5Smjnelson	OLDPWD=$2
1844cdf0c1d5Smjnelson
1845cdf0c1d5Smjnelson	cd $CWS
1846cdf0c1d5Smjnelson	print -u2 " File list from: svn status ... \c"
1847cdf0c1d5Smjnelson	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
1848cdf0c1d5Smjnelson	print -u2 " Done."
1849cdf0c1d5Smjnelson	cd $OLDPWD
1850cdf0c1d5Smjnelson}
1851cdf0c1d5Smjnelson
1852daaffb31Sdpfunction env_from_flist
1853daaffb31Sdp{
1854daaffb31Sdp	[[ -r $FLIST ]] || return
1855daaffb31Sdp
1856daaffb31Sdp	#
1857daaffb31Sdp	# Use "eval" to set env variables that are listed in the file
1858daaffb31Sdp	# list.  Then copy those into our local versions of those
1859daaffb31Sdp	# variables if they have not been set already.
1860daaffb31Sdp	#
1861b0088928SVladimir Kotal	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
18627c478bd9Sstevel@tonic-gate
1863cdf0c1d5Smjnelson	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
1864cdf0c1d5Smjnelson		codemgr_ws=$CODEMGR_WS
1865cdf0c1d5Smjnelson		export CODEMGR_WS
1866cdf0c1d5Smjnelson	fi
18677c478bd9Sstevel@tonic-gate
1868daaffb31Sdp	#
1869daaffb31Sdp	# Check to see if CODEMGR_PARENT is set in the flist file.
1870daaffb31Sdp	#
1871cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
1872daaffb31Sdp		codemgr_parent=$CODEMGR_PARENT
1873cdf0c1d5Smjnelson		export CODEMGR_PARENT
1874daaffb31Sdp	fi
1875daaffb31Sdp}
1876daaffb31Sdp
187714983201Sdpfunction look_for_prog
187814983201Sdp{
187914983201Sdp	typeset path
188014983201Sdp	typeset ppath
188114983201Sdp	typeset progname=$1
188214983201Sdp
188314983201Sdp	ppath=$PATH
188414983201Sdp	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
18853ba097dbSBart Coddens	ppath=$ppath:/opt/onbld/bin
1886cdf0c1d5Smjnelson	ppath=$ppath:/opt/onbld/bin/`uname -p`
188714983201Sdp
188814983201Sdp	PATH=$ppath prog=`whence $progname`
188914983201Sdp	if [[ -n $prog ]]; then
189014983201Sdp		print $prog
189114983201Sdp	fi
189214983201Sdp}
189314983201Sdp
1894cdf0c1d5Smjnelsonfunction get_file_mode
1895cdf0c1d5Smjnelson{
1896cdf0c1d5Smjnelson	$PERL -e '
1897cdf0c1d5Smjnelson		if (@stat = stat($ARGV[0])) {
1898cdf0c1d5Smjnelson			$mode = $stat[2] & 0777;
1899cdf0c1d5Smjnelson			printf "%03o\n", $mode;
1900cdf0c1d5Smjnelson			exit 0;
1901cdf0c1d5Smjnelson		} else {
1902cdf0c1d5Smjnelson			exit 1;
1903cdf0c1d5Smjnelson		}
1904cdf0c1d5Smjnelson	    ' $1
1905cdf0c1d5Smjnelson}
1906cdf0c1d5Smjnelson
1907cdf0c1d5Smjnelsonfunction build_old_new_mercurial
1908cdf0c1d5Smjnelson{
1909cdf0c1d5Smjnelson	typeset olddir="$1"
1910cdf0c1d5Smjnelson	typeset newdir="$2"
1911cdf0c1d5Smjnelson	typeset old_mode=
1912cdf0c1d5Smjnelson	typeset new_mode=
1913cdf0c1d5Smjnelson	typeset file
1914cdf0c1d5Smjnelson
1915cdf0c1d5Smjnelson	#
1916cdf0c1d5Smjnelson	# Get old file mode, from the parent revision manifest entry.
1917cdf0c1d5Smjnelson	# Mercurial only stores a "file is executable" flag, but the
1918cdf0c1d5Smjnelson	# manifest will display an octal mode "644" or "755".
1919cdf0c1d5Smjnelson	#
1920cdf0c1d5Smjnelson	if [[ "$PDIR" == "." ]]; then
1921cdf0c1d5Smjnelson		file="$PF"
1922cdf0c1d5Smjnelson	else
1923cdf0c1d5Smjnelson		file="$PDIR/$PF"
1924cdf0c1d5Smjnelson	fi
1925b0088928SVladimir Kotal	file=`echo $file | $SED 's#/#\\\/#g'`
1926cdf0c1d5Smjnelson	# match the exact filename, and return only the permission digits
1927b0088928SVladimir Kotal	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
1928cdf0c1d5Smjnelson	    < $HG_PARENT_MANIFEST`
1929cdf0c1d5Smjnelson
1930cdf0c1d5Smjnelson	#
1931cdf0c1d5Smjnelson	# Get new file mode, directly from the filesystem.
1932cdf0c1d5Smjnelson	# Normalize the mode to match Mercurial's behavior.
1933cdf0c1d5Smjnelson	#
1934cdf0c1d5Smjnelson	new_mode=`get_file_mode $CWS/$DIR/$F`
1935cdf0c1d5Smjnelson	if [[ -n "$new_mode" ]]; then
1936cdf0c1d5Smjnelson		if [[ "$new_mode" = *[1357]* ]]; then
1937cdf0c1d5Smjnelson			new_mode=755
1938cdf0c1d5Smjnelson		else
1939cdf0c1d5Smjnelson			new_mode=644
1940cdf0c1d5Smjnelson		fi
1941cdf0c1d5Smjnelson	fi
1942cdf0c1d5Smjnelson
1943cdf0c1d5Smjnelson	#
1944cdf0c1d5Smjnelson	# new version of the file.
1945cdf0c1d5Smjnelson	#
1946cdf0c1d5Smjnelson	rm -rf $newdir/$DIR/$F
1947cdf0c1d5Smjnelson	if [[ -e $CWS/$DIR/$F ]]; then
1948cdf0c1d5Smjnelson		cp $CWS/$DIR/$F $newdir/$DIR/$F
1949cdf0c1d5Smjnelson		if [[ -n $new_mode ]]; then
1950cdf0c1d5Smjnelson			chmod $new_mode $newdir/$DIR/$F
1951cdf0c1d5Smjnelson		else
1952cdf0c1d5Smjnelson			# should never happen
1953cdf0c1d5Smjnelson			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
1954cdf0c1d5Smjnelson		fi
1955cdf0c1d5Smjnelson	fi
1956cdf0c1d5Smjnelson
1957cdf0c1d5Smjnelson	#
1958cdf0c1d5Smjnelson	# parent's version of the file
1959cdf0c1d5Smjnelson	#
1960cdf0c1d5Smjnelson	# Note that we get this from the last version common to both
1961cdf0c1d5Smjnelson	# ourselves and the parent.  References are via $CWS since we have no
1962cdf0c1d5Smjnelson	# guarantee that the parent workspace is reachable via the filesystem.
1963cdf0c1d5Smjnelson	#
1964cdf0c1d5Smjnelson	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
1965cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
1966cdf0c1d5Smjnelson	elif [[ -n $HG_PARENT ]]; then
1967cdf0c1d5Smjnelson		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
1968cdf0c1d5Smjnelson		    $olddir/$PDIR/$PF 2>/dev/null
1969cdf0c1d5Smjnelson
197002d26c39SVladimir Kotal		if (( $? != 0 )); then
1971cdf0c1d5Smjnelson			rm -f $olddir/$PDIR/$PF
1972cdf0c1d5Smjnelson		else
1973cdf0c1d5Smjnelson			if [[ -n $old_mode ]]; then
1974cdf0c1d5Smjnelson				chmod $old_mode $olddir/$PDIR/$PF
1975cdf0c1d5Smjnelson			else
1976cdf0c1d5Smjnelson				# should never happen
1977cdf0c1d5Smjnelson				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
1978cdf0c1d5Smjnelson			fi
1979cdf0c1d5Smjnelson		fi
1980cdf0c1d5Smjnelson	fi
1981cdf0c1d5Smjnelson}
1982cdf0c1d5Smjnelson
19838bcea973SRichard Lowefunction build_old_new_git
19848bcea973SRichard Lowe{
19858bcea973SRichard Lowe	typeset olddir="$1"
19868bcea973SRichard Lowe	typeset newdir="$2"
19878bcea973SRichard Lowe	typeset o_mode=
19888bcea973SRichard Lowe	typeset n_mode=
19898bcea973SRichard Lowe	typeset o_object=
19908bcea973SRichard Lowe	typeset n_object=
19918bcea973SRichard Lowe	typeset OWD=$PWD
19928bcea973SRichard Lowe	typeset file
19938bcea973SRichard Lowe	typeset type
19948bcea973SRichard Lowe
19958bcea973SRichard Lowe	cd $CWS
19968bcea973SRichard Lowe
19978bcea973SRichard Lowe	#
19988bcea973SRichard Lowe	# Get old file and its mode from the git object tree
19998bcea973SRichard Lowe	#
20008bcea973SRichard Lowe	if [[ "$PDIR" == "." ]]; then
20018bcea973SRichard Lowe		file="$PF"
20028bcea973SRichard Lowe	else
20038bcea973SRichard Lowe	       file="$PDIR/$PF"
20048bcea973SRichard Lowe	fi
20058bcea973SRichard Lowe
20068bcea973SRichard Lowe	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
20078bcea973SRichard Lowe		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
20088bcea973SRichard Lowe	else
20098bcea973SRichard Lowe                $GIT ls-tree $GIT_PARENT $file | read o_mode type o_object junk
20108bcea973SRichard Lowe                $GIT cat-file $type $o_object > $olddir/$file 2>/dev/null
20118bcea973SRichard Lowe
20128bcea973SRichard Lowe                if (( $? != 0 )); then
20138bcea973SRichard Lowe                        rm -f $olddir/$file
20148bcea973SRichard Lowe                elif [[ -n $o_mode ]]; then
20158bcea973SRichard Lowe                        # Strip the first 3 digits, to get a regular octal mode
20168bcea973SRichard Lowe                        o_mode=${o_mode/???/}
20178bcea973SRichard Lowe                        chmod $o_mode $olddir/$file
20188bcea973SRichard Lowe                else
20198bcea973SRichard Lowe                        # should never happen
20208bcea973SRichard Lowe                        print -u2 "ERROR: set mode of $olddir/$file"
20218bcea973SRichard Lowe                fi
20228bcea973SRichard Lowe	fi
20238bcea973SRichard Lowe
20248bcea973SRichard Lowe	#
20258bcea973SRichard Lowe	# new version of the file.
20268bcea973SRichard Lowe	#
20278bcea973SRichard Lowe	if [[ "$DIR" == "." ]]; then
20288bcea973SRichard Lowe		file="$F"
20298bcea973SRichard Lowe	else
20308bcea973SRichard Lowe		file="$DIR/$F"
20318bcea973SRichard Lowe	fi
20328bcea973SRichard Lowe	rm -rf $newdir/$file
20338bcea973SRichard Lowe
20348bcea973SRichard Lowe        if [[ -e $CWS/$DIR/$F ]]; then
20358bcea973SRichard Lowe            cp $CWS/$DIR/$F $newdir/$DIR/$F
20368bcea973SRichard Lowe            chmod $(get_file_mode $CWS/$DIR/$F) $newdir/$DIR/$F
20378bcea973SRichard Lowe        fi
20388bcea973SRichard Lowe	cd $OWD
20398bcea973SRichard Lowe}
20408bcea973SRichard Lowe
2041cdf0c1d5Smjnelsonfunction build_old_new_subversion
2042cdf0c1d5Smjnelson{
2043cdf0c1d5Smjnelson	typeset olddir="$1"
2044cdf0c1d5Smjnelson	typeset newdir="$2"
2045cdf0c1d5Smjnelson
2046cdf0c1d5Smjnelson	# Snag new version of file.
2047cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2048cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2049cdf0c1d5Smjnelson
2050cdf0c1d5Smjnelson	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
2051cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2052cdf0c1d5Smjnelson	else
2053cdf0c1d5Smjnelson		# Get the parent's version of the file.
2054cdf0c1d5Smjnelson		svn status $CWS/$DIR/$F | read stat file
2055cdf0c1d5Smjnelson		if [[ $stat != "A" ]]; then
2056cdf0c1d5Smjnelson			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
2057cdf0c1d5Smjnelson		fi
2058cdf0c1d5Smjnelson	fi
2059cdf0c1d5Smjnelson}
2060cdf0c1d5Smjnelson
2061cdf0c1d5Smjnelsonfunction build_old_new_unknown
2062cdf0c1d5Smjnelson{
2063cdf0c1d5Smjnelson	typeset olddir="$1"
2064cdf0c1d5Smjnelson	typeset newdir="$2"
2065cdf0c1d5Smjnelson
2066cdf0c1d5Smjnelson	#
2067cdf0c1d5Smjnelson	# Snag new version of file.
2068cdf0c1d5Smjnelson	#
2069cdf0c1d5Smjnelson	rm -f $newdir/$DIR/$F
2070cdf0c1d5Smjnelson	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
2071cdf0c1d5Smjnelson
2072cdf0c1d5Smjnelson	#
2073cdf0c1d5Smjnelson	# Snag the parent's version of the file.
2074cdf0c1d5Smjnelson	#
2075cdf0c1d5Smjnelson	if [[ -f $PWS/$PDIR/$PF ]]; then
2076cdf0c1d5Smjnelson		rm -f $olddir/$PDIR/$PF
2077cdf0c1d5Smjnelson		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
2078cdf0c1d5Smjnelson	fi
2079cdf0c1d5Smjnelson}
2080cdf0c1d5Smjnelson
2081cdf0c1d5Smjnelsonfunction build_old_new
2082cdf0c1d5Smjnelson{
2083cdf0c1d5Smjnelson	typeset WDIR=$1
2084cdf0c1d5Smjnelson	typeset PWS=$2
2085cdf0c1d5Smjnelson	typeset PDIR=$3
2086cdf0c1d5Smjnelson	typeset PF=$4
2087cdf0c1d5Smjnelson	typeset CWS=$5
2088cdf0c1d5Smjnelson	typeset DIR=$6
2089cdf0c1d5Smjnelson	typeset F=$7
2090cdf0c1d5Smjnelson
2091cdf0c1d5Smjnelson	typeset olddir="$WDIR/raw_files/old"
2092cdf0c1d5Smjnelson	typeset newdir="$WDIR/raw_files/new"
2093cdf0c1d5Smjnelson
2094cdf0c1d5Smjnelson	mkdir -p $olddir/$PDIR
2095cdf0c1d5Smjnelson	mkdir -p $newdir/$DIR
2096cdf0c1d5Smjnelson
20973ba097dbSBart Coddens	if [[ $SCM_MODE == "mercurial" ]]; then
2098cdf0c1d5Smjnelson		build_old_new_mercurial "$olddir" "$newdir"
20998bcea973SRichard Lowe	elif [[ $SCM_MODE == "git" ]]; then
21008bcea973SRichard Lowe		build_old_new_git "$olddir" "$newdir"
2101cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "subversion" ]]; then
2102cdf0c1d5Smjnelson		build_old_new_subversion "$olddir" "$newdir"
2103cdf0c1d5Smjnelson	elif [[ $SCM_MODE == "unknown" ]]; then
2104cdf0c1d5Smjnelson		build_old_new_unknown "$olddir" "$newdir"
2105cdf0c1d5Smjnelson	fi
2106cdf0c1d5Smjnelson
2107cdf0c1d5Smjnelson	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
2108cdf0c1d5Smjnelson		print "*** Error: file not in parent or child"
2109cdf0c1d5Smjnelson		return 1
2110cdf0c1d5Smjnelson	fi
2111cdf0c1d5Smjnelson	return 0
2112cdf0c1d5Smjnelson}
2113cdf0c1d5Smjnelson
2114cdf0c1d5Smjnelson
2115daaffb31Sdp#
2116daaffb31Sdp# Usage message.
2117daaffb31Sdp#
2118daaffb31Sdpfunction usage
2119daaffb31Sdp{
2120daaffb31Sdp	print 'Usage:\twebrev [common-options]
2121daaffb31Sdp	webrev [common-options] ( <file> | - )
2122daaffb31Sdp	webrev [common-options] -w <wx file>
2123daaffb31Sdp
2124daaffb31SdpOptions:
21250fd2682eSMark J. Nelson	-C <filename>: Use <filename> for the information tracking configuration.
2126ba44d8a2SVladimir Kotal	-D: delete remote webrev
2127daaffb31Sdp	-i <filename>: Include <filename> in the index.html file.
21280fd2682eSMark J. Nelson	-I <filename>: Use <filename> for the information tracking registry.
2129ba44d8a2SVladimir Kotal	-n: do not generate the webrev (useful with -U)
2130ba44d8a2SVladimir Kotal	-O: Print bugids/arc cases suitable for OpenSolaris.
2131daaffb31Sdp	-o <outdir>: Output webrev to specified directory.
2132daaffb31Sdp	-p <compare-against>: Use specified parent wkspc or basis for comparison
213302d26c39SVladimir Kotal	-t <remote_target>: Specify remote destination for webrev upload
213402d26c39SVladimir Kotal	-U: upload the webrev to remote destination
2135daaffb31Sdp	-w <wxfile>: Use specified wx active file.
2136daaffb31Sdp
2137daaffb31SdpEnvironment:
2138daaffb31Sdp	WDIR: Control the output directory.
2139ba44d8a2SVladimir Kotal	WEBREV_TRASH_DIR: Set directory for webrev delete.
2140daaffb31Sdp
2141daaffb31SdpSCM Environment:
2142cdf0c1d5Smjnelson	CODEMGR_WS: Workspace location.
2143cdf0c1d5Smjnelson	CODEMGR_PARENT: Parent workspace location.
2144daaffb31Sdp'
2145daaffb31Sdp
2146daaffb31Sdp	exit 2
2147daaffb31Sdp}
2148daaffb31Sdp
2149daaffb31Sdp#
2150daaffb31Sdp#
2151daaffb31Sdp# Main program starts here
2152daaffb31Sdp#
2153daaffb31Sdp#
2154daaffb31Sdp
2155daaffb31Sdptrap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
2156daaffb31Sdp
2157daaffb31Sdpset +o noclobber
2158daaffb31Sdp
21598bcea973SRichard LowePATH=$(/bin/dirname "$(whence $0)"):$PATH
2160cdf0c1d5Smjnelson
216114983201Sdp[[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
216214983201Sdp[[ -z $WX ]] && WX=`look_for_prog wx`
2163cdf0c1d5Smjnelson[[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
21648bcea973SRichard Lowe[[ -z $GIT ]] && GIT=`look_for_prog git`
2165cdf0c1d5Smjnelson[[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
216614983201Sdp[[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
216714983201Sdp[[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
216814983201Sdp[[ -z $PERL ]] && PERL=`look_for_prog perl`
216902d26c39SVladimir Kotal[[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
2170cdf0c1d5Smjnelson[[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
2171cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog nawk`
2172cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog gawk`
2173cdf0c1d5Smjnelson[[ -z $AWK ]] && AWK=`look_for_prog awk`
217402d26c39SVladimir Kotal[[ -z $SCP ]] && SCP=`look_for_prog scp`
2175b0088928SVladimir Kotal[[ -z $SED ]] && SED=`look_for_prog sed`
217602d26c39SVladimir Kotal[[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
2177e6ccc173SEdward Pilatowicz[[ -z $SORT ]] && SORT=`look_for_prog sort`
217802d26c39SVladimir Kotal[[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
217902d26c39SVladimir Kotal[[ -z $GREP ]] && GREP=`look_for_prog grep`
2180ba44d8a2SVladimir Kotal[[ -z $FIND ]] && FIND=`look_for_prog find`
21810c108ed9SYuri Pankov[[ -z $MANDOC ]] && MANDOC=`look_for_prog mandoc`
21820c108ed9SYuri Pankov[[ -z $COL ]] && COL=`look_for_prog col`
2183cdf0c1d5Smjnelson
2184ba44d8a2SVladimir Kotal# set name of trash directory for remote webrev deletion
2185ba44d8a2SVladimir KotalTRASH_DIR=".trash"
2186ba44d8a2SVladimir Kotal[[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
218714983201Sdp
218814983201Sdpif [[ ! -x $PERL ]]; then
218914983201Sdp	print -u2 "Error: No perl interpreter found.  Exiting."
219014983201Sdp	exit 1
2191daaffb31Sdpfi
219214983201Sdp
2193cdf0c1d5Smjnelsonif [[ ! -x $WHICH_SCM ]]; then
2194cdf0c1d5Smjnelson	print -u2 "Error: Could not find which_scm.  Exiting."
2195cdf0c1d5Smjnelson	exit 1
2196cdf0c1d5Smjnelsonfi
2197cdf0c1d5Smjnelson
219814983201Sdp#
219914983201Sdp# These aren't fatal, but we want to note them to the user.
220014983201Sdp# We don't warn on the absence of 'wx' until later when we've
220114983201Sdp# determined that we actually need to try to invoke it.
220214983201Sdp#
220314983201Sdp[[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
220414983201Sdp[[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
220514983201Sdp[[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
2206daaffb31Sdp
2207daaffb31Sdp# Declare global total counters.
2208daaffb31Sdpinteger TOTL TINS TDEL TMOD TUNC
2209daaffb31Sdp
2210ba44d8a2SVladimir Kotal# default remote host for upload/delete
2211ba44d8a2SVladimir Kotaltypeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
2212b0088928SVladimir Kotal# prefixes for upload targets
2213b0088928SVladimir Kotaltypeset -r rsync_prefix="rsync://"
2214b0088928SVladimir Kotaltypeset -r ssh_prefix="ssh://"
2215ba44d8a2SVladimir Kotal
22160fd2682eSMark J. NelsonCflag=
2217ba44d8a2SVladimir KotalDflag=
221814983201Sdpflist_mode=
221914983201Sdpflist_file=
2220daaffb31Sdpiflag=
22210fd2682eSMark J. NelsonIflag=
222202d26c39SVladimir Kotallflag=
222302d26c39SVladimir KotalNflag=
222402d26c39SVladimir Kotalnflag=
222502d26c39SVladimir KotalOflag=
2226daaffb31Sdpoflag=
2227daaffb31Sdppflag=
222802d26c39SVladimir Kotaltflag=
222902d26c39SVladimir Kotaluflag=
223002d26c39SVladimir KotalUflag=
2231daaffb31Sdpwflag=
223202d26c39SVladimir Kotalremote_target=
2233ba44d8a2SVladimir Kotal
2234ba44d8a2SVladimir Kotal#
2235ba44d8a2SVladimir Kotal# NOTE: when adding/removing options it is necessary to sync the list
2236ba44d8a2SVladimir Kotal#	with usr/src/tools/onbld/hgext/cdm.py
2237ba44d8a2SVladimir Kotal#
223825cc4e45SVladimir Kotalwhile getopts "C:Di:I:lnNo:Op:t:Uw" opt
2239daaffb31Sdpdo
2240daaffb31Sdp	case $opt in
22410fd2682eSMark J. Nelson	C)	Cflag=1
22420fd2682eSMark J. Nelson		ITSCONF=$OPTARG;;
22430fd2682eSMark J. Nelson
2244ba44d8a2SVladimir Kotal	D)	Dflag=1;;
2245ba44d8a2SVladimir Kotal
2246daaffb31Sdp	i)	iflag=1
2247daaffb31Sdp		INCLUDE_FILE=$OPTARG;;
2248daaffb31Sdp
22490fd2682eSMark J. Nelson	I)	Iflag=1
22500fd2682eSMark J. Nelson		ITSREG=$OPTARG;;
22510fd2682eSMark J. Nelson
225202d26c39SVladimir Kotal	N)	Nflag=1;;
225302d26c39SVladimir Kotal
225402d26c39SVladimir Kotal	n)	nflag=1;;
2255daaffb31Sdp
2256daaffb31Sdp	O)	Oflag=1;;
2257daaffb31Sdp
225802d26c39SVladimir Kotal	o)	oflag=1
22599d3952abSVladimir Kotal		# Strip the trailing slash to correctly form remote target.
22609d3952abSVladimir Kotal		WDIR=${OPTARG%/};;
226102d26c39SVladimir Kotal
226202d26c39SVladimir Kotal	p)	pflag=1
226302d26c39SVladimir Kotal		codemgr_parent=$OPTARG;;
226402d26c39SVladimir Kotal
226502d26c39SVladimir Kotal	t)	tflag=1
226602d26c39SVladimir Kotal		remote_target=$OPTARG;;
226702d26c39SVladimir Kotal
226802d26c39SVladimir Kotal	U)	Uflag=1;;
226902d26c39SVladimir Kotal
227002d26c39SVladimir Kotal	w)	wflag=1;;
22713df69ef3SDarren Moffat
2272daaffb31Sdp	?)	usage;;
2273daaffb31Sdp	esac
2274daaffb31Sdpdone
2275daaffb31Sdp
2276daaffb31SdpFLIST=/tmp/$$.flist
2277daaffb31Sdp
2278daaffb31Sdpif [[ -n $wflag && -n $lflag ]]; then
2279daaffb31Sdp	usage
2280daaffb31Sdpfi
2281daaffb31Sdp
228202d26c39SVladimir Kotal# more sanity checking
228302d26c39SVladimir Kotalif [[ -n $nflag && -z $Uflag ]]; then
2284ba44d8a2SVladimir Kotal	print "it does not make sense to skip webrev generation" \
2285ba44d8a2SVladimir Kotal	    "without -U"
228602d26c39SVladimir Kotal	exit 1
228702d26c39SVladimir Kotalfi
228802d26c39SVladimir Kotal
2289ba44d8a2SVladimir Kotalif [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
2290ba44d8a2SVladimir Kotal	echo "remote target has to be used only for upload or delete"
229102d26c39SVladimir Kotal	exit 1
229202d26c39SVladimir Kotalfi
229302d26c39SVladimir Kotal
2294daaffb31Sdp#
22952d9224a3SMark J. Nelson# For the invocation "webrev -n -U" with no other options, webrev will assume
22962d9224a3SMark J. Nelson# that the webrev exists in ${CWS}/webrev, but will upload it using the name
22972d9224a3SMark J. Nelson# $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
22982d9224a3SMark J. Nelson# logic.
22992d9224a3SMark J. Nelson#
23002d9224a3SMark J. Nelson$WHICH_SCM | read SCM_MODE junk || exit 1
23013ba097dbSBart Coddensif [[ $SCM_MODE == "mercurial" ]]; then
23022d9224a3SMark J. Nelson	#
23032d9224a3SMark J. Nelson	# Mercurial priorities:
23042d9224a3SMark J. Nelson	# 1. hg root from CODEMGR_WS environment variable
230578add226Sjmcp	# 1a. hg root from CODEMGR_WS/usr/closed if we're somewhere under
230678add226Sjmcp	#    usr/closed when we run webrev
23072d9224a3SMark J. Nelson	# 2. hg root from directory of invocation
23082d9224a3SMark J. Nelson	#
230978add226Sjmcp	if [[ ${PWD} =~ "usr/closed" ]]; then
231078add226Sjmcp		testparent=${CODEMGR_WS}/usr/closed
231178add226Sjmcp		# If we're in OpenSolaris mode, we enforce a minor policy:
231278add226Sjmcp		# help to make sure the reviewer doesn't accidentally publish
231378add226Sjmcp		# source which is under usr/closed
231478add226Sjmcp		if [[ -n "$Oflag" ]]; then
231578add226Sjmcp			print -u2 "OpenSolaris output not permitted with" \
231678add226Sjmcp			    "usr/closed changes"
231778add226Sjmcp			exit 1
231878add226Sjmcp		fi
231978add226Sjmcp	else
232078add226Sjmcp	        testparent=${CODEMGR_WS}
232178add226Sjmcp	fi
232278add226Sjmcp	[[ -z $codemgr_ws && -n $testparent ]] && \
232378add226Sjmcp	    codemgr_ws=$(hg root -R $testparent 2>/dev/null)
23242d9224a3SMark J. Nelson	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
23252d9224a3SMark J. Nelson	CWS=$codemgr_ws
23268bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
23278bcea973SRichard Lowe	#
23288bcea973SRichard Lowe	# Git priorities:
23298bcea973SRichard Lowe	# 1. git rev-parse --git-dir from CODEMGR_WS environment variable
23308bcea973SRichard Lowe	# 2. git rev-parse --git-dir from directory of invocation
23318bcea973SRichard Lowe	#
23328bcea973SRichard Lowe	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
23338bcea973SRichard Lowe	    codemgr_ws=$($GIT --git-dir=$CODEMGR_WS/.git rev-parse --git-dir \
23348bcea973SRichard Lowe                2>/dev/null)
23358bcea973SRichard Lowe	[[ -z $codemgr_ws ]] && \
23368bcea973SRichard Lowe	    codemgr_ws=$($GIT rev-parse --git-dir 2>/dev/null)
23378bcea973SRichard Lowe
23388bcea973SRichard Lowe	if [[ "$codemgr_ws" == ".git" ]]; then
23398bcea973SRichard Lowe		codemgr_ws="${PWD}/${codemgr_ws}"
23408bcea973SRichard Lowe	fi
23418bcea973SRichard Lowe
23428bcea973SRichard Lowe	codemgr_ws=$(dirname $codemgr_ws) # Lose the '/.git'
23438bcea973SRichard Lowe	CWS="$codemgr_ws"
23442d9224a3SMark J. Nelsonelif [[ $SCM_MODE == "subversion" ]]; then
23452d9224a3SMark J. Nelson	#
23462d9224a3SMark J. Nelson	# Subversion priorities:
23472d9224a3SMark J. Nelson	# 1. CODEMGR_WS from environment
23482d9224a3SMark J. Nelson	# 2. Relative path from current directory to SVN repository root
23492d9224a3SMark J. Nelson	#
23502d9224a3SMark J. Nelson	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
23512d9224a3SMark J. Nelson		CWS=$CODEMGR_WS
23522d9224a3SMark J. Nelson	else
23532d9224a3SMark J. Nelson		svn info | while read line; do
23542d9224a3SMark J. Nelson			if [[ $line == "URL: "* ]]; then
23552d9224a3SMark J. Nelson				url=${line#URL: }
23562d9224a3SMark J. Nelson			elif [[ $line == "Repository Root: "* ]]; then
23572d9224a3SMark J. Nelson				repo=${line#Repository Root: }
23582d9224a3SMark J. Nelson			fi
23592d9224a3SMark J. Nelson		done
23602d9224a3SMark J. Nelson
23612d9224a3SMark J. Nelson		rel=${url#$repo}
23622d9224a3SMark J. Nelson		CWS=${PWD%$rel}
23632d9224a3SMark J. Nelson	fi
23642d9224a3SMark J. Nelsonfi
23652d9224a3SMark J. Nelson
23662d9224a3SMark J. Nelson#
23672d9224a3SMark J. Nelson# If no SCM has been determined, take either the environment setting
23682d9224a3SMark J. Nelson# setting for CODEMGR_WS, or the current directory if that wasn't set.
23692d9224a3SMark J. Nelson#
23702d9224a3SMark J. Nelsonif [[ -z ${CWS} ]]; then
23712d9224a3SMark J. Nelson	CWS=${CODEMGR_WS:-.}
23722d9224a3SMark J. Nelsonfi
23732d9224a3SMark J. Nelson
23742d9224a3SMark J. Nelson#
23750fd2682eSMark J. Nelson# If the command line options indicate no webrev generation, either
23760fd2682eSMark J. Nelson# explicitly (-n) or implicitly (-D but not -U), then there's a whole
23770fd2682eSMark J. Nelson# ton of logic we can skip.
23780fd2682eSMark J. Nelson#
23790fd2682eSMark J. Nelson# Instead of increasing indentation, we intentionally leave this loop
23800fd2682eSMark J. Nelson# body open here, and exit via break from multiple points within.
23810fd2682eSMark J. Nelson# Search for DO_EVERYTHING below to find the break points and closure.
23820fd2682eSMark J. Nelson#
23830fd2682eSMark J. Nelsonfor do_everything in 1; do
23840fd2682eSMark J. Nelson
23850fd2682eSMark J. Nelson# DO_EVERYTHING: break point
23860fd2682eSMark J. Nelsonif [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
23870fd2682eSMark J. Nelson	break
23880fd2682eSMark J. Nelsonfi
23890fd2682eSMark J. Nelson
23900fd2682eSMark J. Nelson#
2391daaffb31Sdp# If this manually set as the parent, and it appears to be an earlier webrev,
2392daaffb31Sdp# then note that fact and set the parent to the raw_files/new subdirectory.
2393daaffb31Sdp#
2394daaffb31Sdpif [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
23958bcea973SRichard Lowe	parent_webrev=$(readlink -f "$codemgr_parent")
23968bcea973SRichard Lowe	codemgr_parent=$(readlink -f "$codemgr_parent/raw_files/new")
2397daaffb31Sdpfi
2398daaffb31Sdp
2399daaffb31Sdpif [[ -z $wflag && -z $lflag ]]; then
2400daaffb31Sdp	shift $(($OPTIND - 1))
2401daaffb31Sdp
2402daaffb31Sdp	if [[ $1 == "-" ]]; then
2403daaffb31Sdp		cat > $FLIST
240414983201Sdp		flist_mode="stdin"
240514983201Sdp		flist_done=1
240614983201Sdp		shift
2407daaffb31Sdp	elif [[ -n $1 ]]; then
240814983201Sdp		if [[ ! -r $1 ]]; then
2409daaffb31Sdp			print -u2 "$1: no such file or not readable"
2410daaffb31Sdp			usage
2411daaffb31Sdp		fi
2412daaffb31Sdp		cat $1 > $FLIST
241314983201Sdp		flist_mode="file"
241414983201Sdp		flist_file=$1
241514983201Sdp		flist_done=1
241614983201Sdp		shift
2417daaffb31Sdp	else
241814983201Sdp		flist_mode="auto"
2419daaffb31Sdp	fi
2420daaffb31Sdpfi
2421daaffb31Sdp
2422daaffb31Sdp#
2423daaffb31Sdp# Before we go on to further consider -l and -w, work out which SCM we think
2424daaffb31Sdp# is in use.
2425daaffb31Sdp#
2426cdf0c1d5Smjnelsoncase "$SCM_MODE" in
24273ba097dbSBart Coddensmercurial|git|subversion)
2428cdf0c1d5Smjnelson	;;
2429cdf0c1d5Smjnelsonunknown)
2430cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2431cdf0c1d5Smjnelson		print -u2 "Unable to determine SCM in use and file list not specified"
2432cdf0c1d5Smjnelson		print -u2 "See which_scm(1) for SCM detection information."
24337c478bd9Sstevel@tonic-gate		exit 1
24347c478bd9Sstevel@tonic-gate	fi
2435cdf0c1d5Smjnelson	;;
2436cdf0c1d5Smjnelson*)
2437cdf0c1d5Smjnelson	if [[ $flist_mode == "auto" ]]; then
2438cdf0c1d5Smjnelson		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
2439cdf0c1d5Smjnelson		exit 1
2440cdf0c1d5Smjnelson	fi
2441cdf0c1d5Smjnelson	;;
2442cdf0c1d5Smjnelsonesac
24437c478bd9Sstevel@tonic-gate
2444daaffb31Sdpprint -u2 "   SCM detected: $SCM_MODE"
2445daaffb31Sdp
24463ba097dbSBart Coddensif [[ -n $wflag ]]; then
2447daaffb31Sdp	#
2448daaffb31Sdp	# If the -w is given then assume the file list is in Bonwick's "wx"
2449daaffb31Sdp	# command format, i.e.  pathname lines alternating with SCCS comment
2450daaffb31Sdp	# lines with blank lines as separators.  Use the SCCS comments later
2451daaffb31Sdp	# in building the index.html file.
2452daaffb31Sdp	#
2453daaffb31Sdp	shift $(($OPTIND - 1))
2454daaffb31Sdp	wxfile=$1
2455daaffb31Sdp	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
2456daaffb31Sdp		if [[ -r $CODEMGR_WS/wx/active ]]; then
2457daaffb31Sdp			wxfile=$CODEMGR_WS/wx/active
2458daaffb31Sdp		fi
2459daaffb31Sdp	fi
2460daaffb31Sdp
2461daaffb31Sdp	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
2462daaffb31Sdp	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
2463daaffb31Sdp
2464cdf0c1d5Smjnelson	if [[ ! -r $wxfile ]]; then
2465cdf0c1d5Smjnelson		print -u2 "$wxfile: no such file or not readable"
2466cdf0c1d5Smjnelson		usage
2467cdf0c1d5Smjnelson	fi
2468cdf0c1d5Smjnelson
2469daaffb31Sdp	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
2470daaffb31Sdp	flist_from_wx $wxfile
2471daaffb31Sdp	flist_done=1
2472daaffb31Sdp	if [[ -n "$*" ]]; then
2473daaffb31Sdp		shift
2474daaffb31Sdp	fi
247514983201Sdpelif [[ $flist_mode == "stdin" ]]; then
247614983201Sdp	print -u2 " File list from: standard input"
247714983201Sdpelif [[ $flist_mode == "file" ]]; then
247814983201Sdp	print -u2 " File list from: $flist_file"
2479daaffb31Sdpfi
2480daaffb31Sdp
2481daaffb31Sdpif [[ $# -gt 0 ]]; then
248214983201Sdp	print -u2 "WARNING: unused arguments: $*"
2483daaffb31Sdpfi
2484daaffb31Sdp
24852d9224a3SMark J. Nelson#
24862d9224a3SMark J. Nelson# Before we entered the DO_EVERYTHING loop, we should have already set CWS
24872d9224a3SMark J. Nelson# and CODEMGR_WS as needed.  Here, we set the parent workspace.
24882d9224a3SMark J. Nelson#
24893ba097dbSBart Coddensif [[ $SCM_MODE == "mercurial" ]]; then
2490cdf0c1d5Smjnelson	#
2491cdf0c1d5Smjnelson	# Parent can either be specified with -p
2492cdf0c1d5Smjnelson	# Specified with CODEMGR_PARENT in the environment
2493cdf0c1d5Smjnelson	# or taken from hg's default path.
2494cdf0c1d5Smjnelson	#
2495cdf0c1d5Smjnelson
2496cdf0c1d5Smjnelson	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
2497cdf0c1d5Smjnelson		codemgr_parent=$CODEMGR_PARENT
2498cdf0c1d5Smjnelson	fi
2499cdf0c1d5Smjnelson
2500cdf0c1d5Smjnelson	if [[ -z $codemgr_parent ]]; then
2501cdf0c1d5Smjnelson		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
2502cdf0c1d5Smjnelson	fi
2503cdf0c1d5Smjnelson
2504cdf0c1d5Smjnelson	PWS=$codemgr_parent
2505cdf0c1d5Smjnelson
2506cdf0c1d5Smjnelson	#
2507cdf0c1d5Smjnelson	# If the parent is a webrev, we want to do some things against
2508cdf0c1d5Smjnelson	# the natural workspace parent (file list, comments, etc)
2509cdf0c1d5Smjnelson	#
2510cdf0c1d5Smjnelson	if [[ -n $parent_webrev ]]; then
2511cdf0c1d5Smjnelson		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
2512cdf0c1d5Smjnelson	else
2513cdf0c1d5Smjnelson		real_parent=$PWS
2514cdf0c1d5Smjnelson	fi
2515cdf0c1d5Smjnelson
2516cdf0c1d5Smjnelson	#
2517cdf0c1d5Smjnelson	# If hg-active exists, then we run it.  In the case of no explicit
2518cdf0c1d5Smjnelson	# flist given, we'll use it for our comments.  In the case of an
2519cdf0c1d5Smjnelson	# explicit flist given we'll try to use it for comments for any
2520cdf0c1d5Smjnelson	# files mentioned in the flist.
2521cdf0c1d5Smjnelson	#
2522cdf0c1d5Smjnelson	if [[ -z $flist_done ]]; then
2523cdf0c1d5Smjnelson		flist_from_mercurial $CWS $real_parent
2524cdf0c1d5Smjnelson		flist_done=1
2525cdf0c1d5Smjnelson	fi
2526cdf0c1d5Smjnelson
2527cdf0c1d5Smjnelson	#
2528cdf0c1d5Smjnelson	# If we have a file list now, pull out any variables set
2529cdf0c1d5Smjnelson	# therein.  We do this now (rather than when we possibly use
2530cdf0c1d5Smjnelson	# hg-active to find comments) to avoid stomping specifications
2531cdf0c1d5Smjnelson	# in the user-specified flist.
2532cdf0c1d5Smjnelson	#
2533cdf0c1d5Smjnelson	if [[ -n $flist_done ]]; then
2534cdf0c1d5Smjnelson		env_from_flist
2535cdf0c1d5Smjnelson	fi
2536cdf0c1d5Smjnelson
2537cdf0c1d5Smjnelson	#
2538cdf0c1d5Smjnelson	# Only call hg-active if we don't have a wx formatted file already
2539cdf0c1d5Smjnelson	#
2540cdf0c1d5Smjnelson	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
2541cdf0c1d5Smjnelson		print "  Comments from: hg-active -p $real_parent ...\c"
2542cdf0c1d5Smjnelson		hg_active_wxfile $CWS $real_parent
2543cdf0c1d5Smjnelson		print " Done."
2544cdf0c1d5Smjnelson	fi
2545cdf0c1d5Smjnelson
2546cdf0c1d5Smjnelson	#
2547cdf0c1d5Smjnelson	# At this point we must have a wx flist either from hg-active,
2548cdf0c1d5Smjnelson	# or in general.  Use it to try and find our parent revision,
2549cdf0c1d5Smjnelson	# if we don't have one.
2550cdf0c1d5Smjnelson	#
2551cdf0c1d5Smjnelson	if [[ -z $HG_PARENT ]]; then
2552b0088928SVladimir Kotal		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
2553cdf0c1d5Smjnelson	fi
2554cdf0c1d5Smjnelson
2555cdf0c1d5Smjnelson	#
2556cdf0c1d5Smjnelson	# If we still don't have a parent, we must have been given a
2557cdf0c1d5Smjnelson	# wx-style active list with no HG_PARENT specification, run
2558cdf0c1d5Smjnelson	# hg-active and pull an HG_PARENT out of it, ignore the rest.
2559cdf0c1d5Smjnelson	#
2560cdf0c1d5Smjnelson	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
2561cdf0c1d5Smjnelson		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
2562b0088928SVladimir Kotal		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
2563cdf0c1d5Smjnelson	elif [[ -z $HG_PARENT ]]; then
2564cdf0c1d5Smjnelson		print -u2 "Error: Cannot discover parent revision"
2565cdf0c1d5Smjnelson		exit 1
2566cdf0c1d5Smjnelson	fi
25678bcea973SRichard Lowe
25688bcea973SRichard Lowe	pnode=$(trim_digest $HG_PARENT)
25698bcea973SRichard Lowe	PRETTY_PWS="${PWS} (at ${pnode})"
25708bcea973SRichard Lowe	cnode=$(hg parent -R $codemgr_ws --template '{node|short}' \
25718bcea973SRichard Lowe	    2>/dev/null)
25728bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"}
25738bcea973SRichard Loweelif [[ $SCM_MODE == "git" ]]; then
25748bcea973SRichard Lowe	#
25758bcea973SRichard Lowe	# Parent can either be specified with -p, or specified with
25768bcea973SRichard Lowe	# CODEMGR_PARENT in the environment.
25778bcea973SRichard Lowe	#
25788bcea973SRichard Lowe
25798bcea973SRichard Lowe	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
25808bcea973SRichard Lowe		codemgr_parent=$CODEMGR_PARENT
25818bcea973SRichard Lowe	fi
25828bcea973SRichard Lowe
25838bcea973SRichard Lowe	# Try to figure out the parent based on the branch the current
25848bcea973SRichard Lowe	# branch is tracking, if we fail, use origin/master
25858bcea973SRichard Lowe	this_branch=$($GIT branch | nawk '$1 == "*" { print $2 }')
25868bcea973SRichard Lowe	par_branch="origin/master"
25878bcea973SRichard Lowe
25888bcea973SRichard Lowe        # If we're not on a branch there's nothing we can do
25898bcea973SRichard Lowe        if [[ $this_branch != "(no branch)" ]]; then
25908bcea973SRichard Lowe                $GIT for-each-ref                                                 \
25918bcea973SRichard Lowe                    --format='%(refname:short) %(upstream:short)' refs/heads/ |   \
25928bcea973SRichard Lowe                    while read local remote; do                                   \
25938bcea973SRichard Lowe                	[[ "$local" == "$this_branch" ]] && par_branch="$remote"; \
25948bcea973SRichard Lowe                    done
25958bcea973SRichard Lowe	fi
25968bcea973SRichard Lowe
25978bcea973SRichard Lowe	if [[ -z $codemgr_parent ]]; then
25988bcea973SRichard Lowe		codemgr_parent=$par_branch
25998bcea973SRichard Lowe	fi
26008bcea973SRichard Lowe	PWS=$codemgr_parent
26018bcea973SRichard Lowe
26028bcea973SRichard Lowe	#
26038bcea973SRichard Lowe	# If the parent is a webrev, we want to do some things against
26048bcea973SRichard Lowe	# the natural workspace parent (file list, comments, etc)
26058bcea973SRichard Lowe	#
26068bcea973SRichard Lowe	if [[ -n $parent_webrev ]]; then
26078bcea973SRichard Lowe		real_parent=$par_branch
26088bcea973SRichard Lowe	else
26098bcea973SRichard Lowe		real_parent=$PWS
26108bcea973SRichard Lowe	fi
26118bcea973SRichard Lowe
26128bcea973SRichard Lowe	if [[ -z $flist_done ]]; then
26138bcea973SRichard Lowe		flist_from_git "$CWS" "$real_parent"
26148bcea973SRichard Lowe		flist_done=1
26158bcea973SRichard Lowe	fi
26168bcea973SRichard Lowe
26178bcea973SRichard Lowe	#
26188bcea973SRichard Lowe	# If we have a file list now, pull out any variables set
26198bcea973SRichard Lowe	# therein.
26208bcea973SRichard Lowe	#
26218bcea973SRichard Lowe	if [[ -n $flist_done ]]; then
26228bcea973SRichard Lowe		env_from_flist
26238bcea973SRichard Lowe	fi
26248bcea973SRichard Lowe
26258bcea973SRichard Lowe	#
26268bcea973SRichard Lowe	# If we don't have a wx-format file list, build one we can pull change
26278bcea973SRichard Lowe	# comments from.
26288bcea973SRichard Lowe	#
26298bcea973SRichard Lowe	if [[ -z $wxfile ]]; then
26308bcea973SRichard Lowe		print "  Comments from: git...\c"
26318bcea973SRichard Lowe		git_wxfile "$CWS" "$real_parent"
26328bcea973SRichard Lowe		print " Done."
26338bcea973SRichard Lowe	fi
26348bcea973SRichard Lowe
26358bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
26368bcea973SRichard Lowe		GIT_PARENT=$($GIT merge-base "$real_parent" HEAD)
26378bcea973SRichard Lowe	fi
26388bcea973SRichard Lowe	if [[ -z $GIT_PARENT ]]; then
26398bcea973SRichard Lowe		print -u2 "Error: Cannot discover parent revision"
26408bcea973SRichard Lowe		exit 1
26418bcea973SRichard Lowe	fi
26428bcea973SRichard Lowe
26438bcea973SRichard Lowe	pnode=$(trim_digest $GIT_PARENT)
26448bcea973SRichard Lowe
26458bcea973SRichard Lowe	if [[ $real_parent == */* ]]; then
26468bcea973SRichard Lowe		origin=$(echo $real_parent | cut -d/ -f1)
26478bcea973SRichard Lowe		origin=$($GIT remote -v | \
26488bcea973SRichard Lowe		    $AWK '$1 == "'$origin'" { print $2; exit }')
26498bcea973SRichard Lowe		PRETTY_PWS="${PWS} (${origin} at ${pnode})"
26508bcea973SRichard Lowe	else
26518bcea973SRichard Lowe		PRETTY_PWS="${PWS} (at ${pnode})"
26528bcea973SRichard Lowe	fi
26538bcea973SRichard Lowe
26548bcea973SRichard Lowe	cnode=$($GIT --git-dir=${codemgr_ws}/.git rev-parse --short=12 HEAD \
26558bcea973SRichard Lowe	    2>/dev/null)
26568bcea973SRichard Lowe	PRETTY_CWS="${CWS} (at ${cnode})"
2657cdf0c1d5Smjnelsonelif [[ $SCM_MODE == "subversion" ]]; then
2658cdf0c1d5Smjnelson
2659cdf0c1d5Smjnelson	#
2660cdf0c1d5Smjnelson	# We only will have a real parent workspace in the case one
2661cdf0c1d5Smjnelson	# was specified (be it an older webrev, or another checkout).
2662cdf0c1d5Smjnelson	#
2663cdf0c1d5Smjnelson	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
2664cdf0c1d5Smjnelson
2665cdf0c1d5Smjnelson	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
2666cdf0c1d5Smjnelson		flist_from_subversion $CWS $OLDPWD
2667cdf0c1d5Smjnelson	fi
2668cdf0c1d5Smjnelsonelse
2669cdf0c1d5Smjnelson    if [[ $SCM_MODE == "unknown" ]]; then
2670cdf0c1d5Smjnelson	print -u2 "    Unknown type of SCM in use"
2671cdf0c1d5Smjnelson    else
2672cdf0c1d5Smjnelson	print -u2 "    Unsupported SCM in use: $SCM_MODE"
2673cdf0c1d5Smjnelson    fi
2674cdf0c1d5Smjnelson
2675cdf0c1d5Smjnelson    env_from_flist
2676cdf0c1d5Smjnelson
2677cdf0c1d5Smjnelson    if [[ -z $CODEMGR_WS ]]; then
2678cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
2679cdf0c1d5Smjnelson	exit 1
2680cdf0c1d5Smjnelson    fi
2681cdf0c1d5Smjnelson
2682cdf0c1d5Smjnelson    if [[ -z $CODEMGR_PARENT ]]; then
2683cdf0c1d5Smjnelson	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
2684cdf0c1d5Smjnelson	exit 1
2685cdf0c1d5Smjnelson    fi
2686cdf0c1d5Smjnelson
2687cdf0c1d5Smjnelson    CWS=$CODEMGR_WS
2688cdf0c1d5Smjnelson    PWS=$CODEMGR_PARENT
2689daaffb31Sdpfi
2690daaffb31Sdp
2691daaffb31Sdp#
2692daaffb31Sdp# If the user didn't specify a -i option, check to see if there is a
2693daaffb31Sdp# webrev-info file in the workspace directory.
2694daaffb31Sdp#
2695daaffb31Sdpif [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
2696daaffb31Sdp	iflag=1
2697daaffb31Sdp	INCLUDE_FILE="$CWS/webrev-info"
2698daaffb31Sdpfi
2699daaffb31Sdp
2700daaffb31Sdpif [[ -n $iflag ]]; then
2701daaffb31Sdp	if [[ ! -r $INCLUDE_FILE ]]; then
2702daaffb31Sdp		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
2703daaffb31Sdp		    "not readable."
2704daaffb31Sdp		exit 1
2705daaffb31Sdp	else
2706daaffb31Sdp		#
2707daaffb31Sdp		# $INCLUDE_FILE may be a relative path, and the script alters
2708daaffb31Sdp		# PWD, so we just stash a copy in /tmp.
2709daaffb31Sdp		#
2710daaffb31Sdp		cp $INCLUDE_FILE /tmp/$$.include
2711daaffb31Sdp	fi
2712daaffb31Sdpfi
2713daaffb31Sdp
27140fd2682eSMark J. Nelson# DO_EVERYTHING: break point
27150fd2682eSMark J. Nelsonif [[ -n $Nflag ]]; then
27160fd2682eSMark J. Nelson	break
27170fd2682eSMark J. Nelsonfi
27180fd2682eSMark J. Nelson
27190fd2682eSMark J. Nelsontypeset -A itsinfo
27200fd2682eSMark J. Nelsontypeset -r its_sed_script=/tmp/$$.its_sed
27210fd2682eSMark J. Nelsonvalid_prefixes=
27220fd2682eSMark J. Nelsonif [[ -z $nflag ]]; then
27238bcea973SRichard Lowe	DEFREGFILE="$(/bin/dirname "$(whence $0)")/../etc/its.reg"
27240fd2682eSMark J. Nelson	if [[ -n $Iflag ]]; then
27250fd2682eSMark J. Nelson		REGFILE=$ITSREG
27260fd2682eSMark J. Nelson	elif [[ -r $HOME/.its.reg ]]; then
27270fd2682eSMark J. Nelson		REGFILE=$HOME/.its.reg
27280fd2682eSMark J. Nelson	else
27290fd2682eSMark J. Nelson		REGFILE=$DEFREGFILE
27300fd2682eSMark J. Nelson	fi
27310fd2682eSMark J. Nelson	if [[ ! -r $REGFILE ]]; then
27320fd2682eSMark J. Nelson		print "ERROR: Unable to read database registry file $REGFILE"
27330fd2682eSMark J. Nelson		exit 1
27340fd2682eSMark J. Nelson	elif [[ $REGFILE != $DEFREGFILE ]]; then
27350fd2682eSMark J. Nelson		print "   its.reg from: $REGFILE"
27360fd2682eSMark J. Nelson	fi
27370fd2682eSMark J. Nelson
27380fd2682eSMark J. Nelson	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
27390fd2682eSMark J. Nelson
27400fd2682eSMark J. Nelson		name=${LINE%%=*}
27410fd2682eSMark J. Nelson		value="${LINE#*=}"
27420fd2682eSMark J. Nelson
27430fd2682eSMark J. Nelson		if [[ $name == PREFIX ]]; then
27440fd2682eSMark J. Nelson			p=${value}
27450fd2682eSMark J. Nelson			valid_prefixes="${p} ${valid_prefixes}"
27460fd2682eSMark J. Nelson		else
27470fd2682eSMark J. Nelson			itsinfo["${p}_${name}"]="${value}"
27480fd2682eSMark J. Nelson		fi
27490fd2682eSMark J. Nelson	done
27500fd2682eSMark J. Nelson
27510fd2682eSMark J. Nelson
27528bcea973SRichard Lowe	DEFCONFFILE="$(/bin/dirname "$(whence $0)")/../etc/its.conf"
27530fd2682eSMark J. Nelson	CONFFILES=$DEFCONFFILE
27540fd2682eSMark J. Nelson	if [[ -r $HOME/.its.conf ]]; then
27550fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} $HOME/.its.conf"
27560fd2682eSMark J. Nelson	fi
27570fd2682eSMark J. Nelson	if [[ -n $Cflag ]]; then
27580fd2682eSMark J. Nelson		CONFFILES="${CONFFILES} ${ITSCONF}"
27590fd2682eSMark J. Nelson	fi
27600fd2682eSMark J. Nelson	its_domain=
27610fd2682eSMark J. Nelson	its_priority=
27620fd2682eSMark J. Nelson	for cf in ${CONFFILES}; do
27630fd2682eSMark J. Nelson		if [[ ! -r $cf ]]; then
27640fd2682eSMark J. Nelson			print "ERROR: Unable to read database configuration file $cf"
27650fd2682eSMark J. Nelson			exit 1
27660fd2682eSMark J. Nelson		elif [[ $cf != $DEFCONFFILE ]]; then
27670fd2682eSMark J. Nelson			print "       its.conf: reading $cf"
27680fd2682eSMark J. Nelson		fi
27690fd2682eSMark J. Nelson		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
27700fd2682eSMark J. Nelson		    eval "${LINE}"
27710fd2682eSMark J. Nelson		done
27720fd2682eSMark J. Nelson	done
27730fd2682eSMark J. Nelson
27740fd2682eSMark J. Nelson	#
27750fd2682eSMark J. Nelson	# If an information tracking system is explicitly identified by prefix,
27760fd2682eSMark J. Nelson	# we want to disregard the specified priorities and resolve it accordingly.
27770fd2682eSMark J. Nelson	#
27780fd2682eSMark J. Nelson	# To that end, we'll build a sed script to do each valid prefix in turn.
27790fd2682eSMark J. Nelson	#
27800fd2682eSMark J. Nelson	for p in ${valid_prefixes}; do
27810fd2682eSMark J. Nelson		#
27820fd2682eSMark J. Nelson		# When an informational URL was provided, translate it to a
27830fd2682eSMark J. Nelson		# hyperlink.  When omitted, simply use the prefix text.
27840fd2682eSMark J. Nelson		#
27850fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
27860fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]=${p}
27870fd2682eSMark J. Nelson		else
27880fd2682eSMark J. Nelson			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
27890fd2682eSMark J. Nelson		fi
27900fd2682eSMark J. Nelson
27910fd2682eSMark J. Nelson		#
27920fd2682eSMark J. Nelson		# Assume that, for this invocation of webrev, all references
27930fd2682eSMark J. Nelson		# to this information tracking system should resolve through
27940fd2682eSMark J. Nelson		# the same URL.
27950fd2682eSMark J. Nelson		#
27960fd2682eSMark J. Nelson		# If the caller specified -O, then always use EXTERNAL_URL.
27970fd2682eSMark J. Nelson		#
27980fd2682eSMark J. Nelson		# Otherwise, look in the list of domains for a matching
27990fd2682eSMark J. Nelson		# INTERNAL_URL.
28000fd2682eSMark J. Nelson		#
28010fd2682eSMark J. Nelson		[[ -z $Oflag ]] && for d in ${its_domain}; do
28020fd2682eSMark J. Nelson			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
28030fd2682eSMark J. Nelson				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
28040fd2682eSMark J. Nelson				break
28050fd2682eSMark J. Nelson			fi
28060fd2682eSMark J. Nelson		done
28070fd2682eSMark J. Nelson		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
28080fd2682eSMark J. Nelson			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
28090fd2682eSMark J. Nelson		fi
28100fd2682eSMark J. Nelson
28110fd2682eSMark J. Nelson		#
28120fd2682eSMark J. Nelson		# Turn the destination URL into a hyperlink
28130fd2682eSMark J. Nelson		#
28140fd2682eSMark J. Nelson		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
28150fd2682eSMark J. Nelson
28162f54b716SRichard Lowe		# The character class below contains a literal tab
28172f54b716SRichard Lowe		print "/^${p}[: 	]/ {
28180fd2682eSMark J. Nelson				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
28190fd2682eSMark J. Nelson				s;^${p};${itsinfo[${p}_INFO]};
28200fd2682eSMark J. Nelson			}" >> ${its_sed_script}
28210fd2682eSMark J. Nelson	done
28220fd2682eSMark J. Nelson
28230fd2682eSMark J. Nelson	#
28240fd2682eSMark J. Nelson	# The previous loop took care of explicit specification.  Now use
28250fd2682eSMark J. Nelson	# the configured priorities to attempt implicit translations.
28260fd2682eSMark J. Nelson	#
28270fd2682eSMark J. Nelson	for p in ${its_priority}; do
28280fd2682eSMark J. Nelson		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
28292f54b716SRichard Lowe				s;^${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
28300fd2682eSMark J. Nelson			}" >> ${its_sed_script}
28310fd2682eSMark J. Nelson	done
28320fd2682eSMark J. Nelsonfi
28330fd2682eSMark J. Nelson
28340fd2682eSMark J. Nelson#
28350fd2682eSMark J. Nelson# Search for DO_EVERYTHING above for matching "for" statement
28360fd2682eSMark J. Nelson# and explanation of this terminator.
28370fd2682eSMark J. Nelson#
28380fd2682eSMark J. Nelsondone
28390fd2682eSMark J. Nelson
2840daaffb31Sdp#
2841daaffb31Sdp# Output directory.
2842daaffb31Sdp#
2843daaffb31SdpWDIR=${WDIR:-$CWS/webrev}
2844daaffb31Sdp
2845daaffb31Sdp#
284602d26c39SVladimir Kotal# Name of the webrev, derived from the workspace name or output directory;
284702d26c39SVladimir Kotal# in the future this could potentially be an option.
2848daaffb31Sdp#
284902d26c39SVladimir Kotalif [[ -n $oflag ]]; then
285002d26c39SVladimir Kotal	WNAME=${WDIR##*/}
285102d26c39SVladimir Kotalelse
2852daaffb31Sdp	WNAME=${CWS##*/}
285302d26c39SVladimir Kotalfi
285402d26c39SVladimir Kotal
2855ba44d8a2SVladimir Kotal# Make sure remote target is well formed for remote upload/delete.
2856ba44d8a2SVladimir Kotalif [[ -n $Dflag || -n $Uflag ]]; then
2857b0088928SVladimir Kotal	#
2858ba44d8a2SVladimir Kotal	# If remote target is not specified, build it from scratch using
2859ba44d8a2SVladimir Kotal	# the default values.
2860b0088928SVladimir Kotal	#
2861ba44d8a2SVladimir Kotal	if [[ -z $tflag ]]; then
2862ba44d8a2SVladimir Kotal		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
2863ba44d8a2SVladimir Kotal	else
2864b0088928SVladimir Kotal		#
2865b0088928SVladimir Kotal		# Check upload target prefix first.
2866b0088928SVladimir Kotal		#
2867b0088928SVladimir Kotal		if [[ "${remote_target}" != ${rsync_prefix}* &&
2868b0088928SVladimir Kotal		    "${remote_target}" != ${ssh_prefix}* ]]; then
2869b0088928SVladimir Kotal			print "ERROR: invalid prefix of upload URI" \
2870b0088928SVladimir Kotal			    "($remote_target)"
2871b0088928SVladimir Kotal			exit 1
2872b0088928SVladimir Kotal		fi
2873b0088928SVladimir Kotal		#
2874ba44d8a2SVladimir Kotal		# If destination specification is not in the form of
2875ba44d8a2SVladimir Kotal		# host_spec:remote_dir then assume it is just remote hostname
2876ba44d8a2SVladimir Kotal		# and append a colon and destination directory formed from
2877ba44d8a2SVladimir Kotal		# local webrev directory name.
2878b0088928SVladimir Kotal		#
2879b0088928SVladimir Kotal		typeset target_no_prefix=${remote_target##*://}
2880b0088928SVladimir Kotal		if [[ ${target_no_prefix} == *:* ]]; then
2881ba44d8a2SVladimir Kotal			if [[ "${remote_target}" == *: ]]; then
2882b0088928SVladimir Kotal				remote_target=${remote_target}${WNAME}
2883ba44d8a2SVladimir Kotal			fi
2884b0088928SVladimir Kotal		else
2885b0088928SVladimir Kotal			if [[ ${target_no_prefix} == */* ]]; then
2886b0088928SVladimir Kotal				print "ERROR: badly formed upload URI" \
2887b0088928SVladimir Kotal					"($remote_target)"
2888b0088928SVladimir Kotal				exit 1
2889b0088928SVladimir Kotal			else
2890b0088928SVladimir Kotal				remote_target=${remote_target}:${WNAME}
2891ba44d8a2SVladimir Kotal			fi
2892ba44d8a2SVladimir Kotal		fi
2893ba44d8a2SVladimir Kotal	fi
2894ba44d8a2SVladimir Kotal
2895b0088928SVladimir Kotal	#
2896b0088928SVladimir Kotal	# Strip trailing slash. Each upload method will deal with directory
2897b0088928SVladimir Kotal	# specification separately.
2898b0088928SVladimir Kotal	#
2899b0088928SVladimir Kotal	remote_target=${remote_target%/}
2900b0088928SVladimir Kotalfi
2901b0088928SVladimir Kotal
2902b0088928SVladimir Kotal#
2903ba44d8a2SVladimir Kotal# Option -D by itself (option -U not present) implies no webrev generation.
2904b0088928SVladimir Kotal#
2905ba44d8a2SVladimir Kotalif [[ -z $Uflag && -n $Dflag ]]; then
2906b0088928SVladimir Kotal	delete_webrev 1 1
2907ba44d8a2SVladimir Kotal	exit $?
2908ba44d8a2SVladimir Kotalfi
2909ba44d8a2SVladimir Kotal
2910b0088928SVladimir Kotal#
2911ba44d8a2SVladimir Kotal# Do not generate the webrev, just upload it or delete it.
2912b0088928SVladimir Kotal#
2913ba44d8a2SVladimir Kotalif [[ -n $nflag ]]; then
2914ba44d8a2SVladimir Kotal	if [[ -n $Dflag ]]; then
2915b0088928SVladimir Kotal		delete_webrev 1 1
2916ba44d8a2SVladimir Kotal		(( $? == 0 )) || exit $?
2917ba44d8a2SVladimir Kotal	fi
2918ba44d8a2SVladimir Kotal	if [[ -n $Uflag ]]; then
291902d26c39SVladimir Kotal		upload_webrev
292002d26c39SVladimir Kotal		exit $?
292102d26c39SVladimir Kotal	fi
2922ba44d8a2SVladimir Kotalfi
2923daaffb31Sdp
2924e0e0293aSjmcpif [ "${WDIR%%/*}" ]; then
29257c478bd9Sstevel@tonic-gate	WDIR=$PWD/$WDIR
29267c478bd9Sstevel@tonic-gatefi
2927daaffb31Sdp
2928daaffb31Sdpif [[ ! -d $WDIR ]]; then
2929daaffb31Sdp	mkdir -p $WDIR
2930ba44d8a2SVladimir Kotal	(( $? != 0 )) && exit 1
29317c478bd9Sstevel@tonic-gatefi
29327c478bd9Sstevel@tonic-gate
2933daaffb31Sdp#
2934daaffb31Sdp# Summarize what we're going to do.
2935daaffb31Sdp#
29368bcea973SRichard Loweprint "      Workspace: ${PRETTY_CWS:-$CWS}"
2937daaffb31Sdpif [[ -n $parent_webrev ]]; then
2938daaffb31Sdp	print "Compare against: webrev at $parent_webrev"
2939daaffb31Sdpelse
29408bcea973SRichard Lowe	print "Compare against: ${PRETTY_PWS:-$PWS}"
2941cdf0c1d5Smjnelsonfi
2942daaffb31Sdp
2943daaffb31Sdp[[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
2944daaffb31Sdpprint "      Output to: $WDIR"
2945daaffb31Sdp
2946daaffb31Sdp#
29477c478bd9Sstevel@tonic-gate# Save the file list in the webrev dir
2948daaffb31Sdp#
2949daaffb31Sdp[[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
29507c478bd9Sstevel@tonic-gate
2951daaffb31Sdprm -f $WDIR/$WNAME.patch
2952daaffb31Sdprm -f $WDIR/$WNAME.ps
2953daaffb31Sdprm -f $WDIR/$WNAME.pdf
29547c478bd9Sstevel@tonic-gate
2955daaffb31Sdptouch $WDIR/$WNAME.patch
29567c478bd9Sstevel@tonic-gate
2957daaffb31Sdpprint "   Output Files:"
2958daaffb31Sdp
2959daaffb31Sdp#
2960daaffb31Sdp# Clean up the file list: Remove comments, blank lines and env variables.
2961daaffb31Sdp#
2962b0088928SVladimir Kotal$SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
2963daaffb31SdpFLIST=/tmp/$$.flist.clean
2964daaffb31Sdp
2965daaffb31Sdp#
2966cdf0c1d5Smjnelson# For Mercurial, create a cache of manifest entries.
2967cdf0c1d5Smjnelson#
2968cdf0c1d5Smjnelsonif [[ $SCM_MODE == "mercurial" ]]; then
2969cdf0c1d5Smjnelson	#
2970cdf0c1d5Smjnelson	# Transform the FLIST into a temporary sed script that matches
2971cdf0c1d5Smjnelson	# relevant entries in the Mercurial manifest as follows:
2972cdf0c1d5Smjnelson	# 1) The script will be used against the parent revision manifest,
2973cdf0c1d5Smjnelson	#    so for FLIST lines that have two filenames (a renamed file)
2974cdf0c1d5Smjnelson	#    keep only the old name.
2975cdf0c1d5Smjnelson	# 2) Escape all forward slashes the filename.
2976cdf0c1d5Smjnelson	# 3) Change the filename into another sed command that matches
2977cdf0c1d5Smjnelson	#    that file in "hg manifest -v" output:  start of line, three
2978cdf0c1d5Smjnelson	#    octal digits for file permissions, space, a file type flag
2979cdf0c1d5Smjnelson	#    character, space, the filename, end of line.
2980e6ccc173SEdward Pilatowicz	# 4) Eliminate any duplicate entries.  (This can occur if a
2981e6ccc173SEdward Pilatowicz	#    file has been used as the source of an hg cp and it's
2982e6ccc173SEdward Pilatowicz	#    also been modified in the same changeset.)
2983cdf0c1d5Smjnelson	#
2984cdf0c1d5Smjnelson	SEDFILE=/tmp/$$.manifest.sed
2985b0088928SVladimir Kotal	$SED '
2986cdf0c1d5Smjnelson		s#^[^ ]* ##
2987cdf0c1d5Smjnelson		s#/#\\\/#g
2988cdf0c1d5Smjnelson		s#^.*$#/^... . &$/p#
2989e6ccc173SEdward Pilatowicz	' < $FLIST | $SORT -u > $SEDFILE
2990cdf0c1d5Smjnelson
2991cdf0c1d5Smjnelson	#
2992cdf0c1d5Smjnelson	# Apply the generated script to the output of "hg manifest -v"
2993cdf0c1d5Smjnelson	# to get the relevant subset for this webrev.
2994cdf0c1d5Smjnelson	#
2995cdf0c1d5Smjnelson	HG_PARENT_MANIFEST=/tmp/$$.manifest
2996cdf0c1d5Smjnelson	hg -R $CWS manifest -v -r $HG_PARENT |
2997b0088928SVladimir Kotal	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
2998cdf0c1d5Smjnelsonfi
2999cdf0c1d5Smjnelson
3000cdf0c1d5Smjnelson#
3001daaffb31Sdp# First pass through the files: generate the per-file webrev HTML-files.
3002daaffb31Sdp#
3003daaffb31Sdpcat $FLIST | while read LINE
30047c478bd9Sstevel@tonic-gatedo
30057c478bd9Sstevel@tonic-gate	set - $LINE
30067c478bd9Sstevel@tonic-gate	P=$1
30077c478bd9Sstevel@tonic-gate
3008daaffb31Sdp	#
3009daaffb31Sdp	# Normally, each line in the file list is just a pathname of a
3010daaffb31Sdp	# file that has been modified or created in the child.  A file
3011daaffb31Sdp	# that is renamed in the child workspace has two names on the
3012daaffb31Sdp	# line: new name followed by the old name.
3013daaffb31Sdp	#
3014daaffb31Sdp	oldname=""
3015daaffb31Sdp	oldpath=""
3016daaffb31Sdp	rename=
3017daaffb31Sdp	if [[ $# -eq 2 ]]; then
30187c478bd9Sstevel@tonic-gate		PP=$2			# old filename
3019e6ccc173SEdward Pilatowicz		if [[ -f $PP ]]; then
3020e6ccc173SEdward Pilatowicz			oldname=" (copied from $PP)"
3021e6ccc173SEdward Pilatowicz		else
3022e6ccc173SEdward Pilatowicz			oldname=" (renamed from $PP)"
3023e6ccc173SEdward Pilatowicz		fi
3024daaffb31Sdp		oldpath="$PP"
3025daaffb31Sdp		rename=1
30267c478bd9Sstevel@tonic-gate		PDIR=${PP%/*}
3027daaffb31Sdp		if [[ $PDIR == $PP ]]; then
30287c478bd9Sstevel@tonic-gate			PDIR="."   # File at root of workspace
30297c478bd9Sstevel@tonic-gate		fi
30307c478bd9Sstevel@tonic-gate
30317c478bd9Sstevel@tonic-gate		PF=${PP##*/}
30327c478bd9Sstevel@tonic-gate
30337c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3034daaffb31Sdp		if [[ $DIR == $P ]]; then
30357c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
30367c478bd9Sstevel@tonic-gate		fi
30377c478bd9Sstevel@tonic-gate
30387c478bd9Sstevel@tonic-gate		F=${P##*/}
3039daaffb31Sdp
30407c478bd9Sstevel@tonic-gate        else
30417c478bd9Sstevel@tonic-gate		DIR=${P%/*}
3042daaffb31Sdp		if [[ "$DIR" == "$P" ]]; then
30437c478bd9Sstevel@tonic-gate			DIR="."   # File at root of workspace
30447c478bd9Sstevel@tonic-gate		fi
30457c478bd9Sstevel@tonic-gate
30467c478bd9Sstevel@tonic-gate		F=${P##*/}
30477c478bd9Sstevel@tonic-gate
30487c478bd9Sstevel@tonic-gate		PP=$P
30497c478bd9Sstevel@tonic-gate		PDIR=$DIR
30507c478bd9Sstevel@tonic-gate		PF=$F
30517c478bd9Sstevel@tonic-gate	fi
30527c478bd9Sstevel@tonic-gate
3053daaffb31Sdp	COMM=`getcomments html $P $PP`
30547c478bd9Sstevel@tonic-gate
3055daaffb31Sdp	print "\t$P$oldname\n\t\t\c"
30567c478bd9Sstevel@tonic-gate
30577c478bd9Sstevel@tonic-gate	# Make the webrev mirror directory if necessary
30587c478bd9Sstevel@tonic-gate	mkdir -p $WDIR/$DIR
30597c478bd9Sstevel@tonic-gate
3060daaffb31Sdp	#
3061cdf0c1d5Smjnelson	# We stash old and new files into parallel directories in $WDIR
3062daaffb31Sdp	# and do our diffs there.  This makes it possible to generate
3063daaffb31Sdp	# clean looking diffs which don't have absolute paths present.
3064daaffb31Sdp	#
3065daaffb31Sdp
3066cdf0c1d5Smjnelson	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
30677c478bd9Sstevel@tonic-gate	    continue
30687c478bd9Sstevel@tonic-gate
3069cdf0c1d5Smjnelson	#
3070cdf0c1d5Smjnelson	# Keep the old PWD around, so we can safely switch back after
3071cdf0c1d5Smjnelson	# diff generation, such that build_old_new runs in a
3072cdf0c1d5Smjnelson	# consistent environment.
3073cdf0c1d5Smjnelson	#
3074cdf0c1d5Smjnelson	OWD=$PWD
3075daaffb31Sdp	cd $WDIR/raw_files
3076daaffb31Sdp	ofile=old/$PDIR/$PF
3077daaffb31Sdp	nfile=new/$DIR/$F
30787c478bd9Sstevel@tonic-gate
3079daaffb31Sdp	mv_but_nodiff=
3080daaffb31Sdp	cmp $ofile $nfile > /dev/null 2>&1
3081daaffb31Sdp	if [[ $? == 0 && $rename == 1 ]]; then
3082daaffb31Sdp		mv_but_nodiff=1
3083daaffb31Sdp	fi
3084daaffb31Sdp
3085daaffb31Sdp	#
3086daaffb31Sdp	# If we have old and new versions of the file then run the appropriate
3087daaffb31Sdp	# diffs.  This is complicated by a couple of factors:
3088daaffb31Sdp	#
3089daaffb31Sdp	#	- renames must be handled specially: we emit a 'remove'
3090daaffb31Sdp	#	  diff and an 'add' diff
3091daaffb31Sdp	#	- new files and deleted files must be handled specially
30920c108ed9SYuri Pankov	#       - GNU patch doesn't interpret the output of illumos diff
30930c108ed9SYuri Pankov	#	  properly when it comes to adds and deletes.  We need to
30940c108ed9SYuri Pankov	#	  do some "cleansing" transformations:
3095daaffb31Sdp	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
3096daaffb31Sdp	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
3097daaffb31Sdp	#
3098b0088928SVladimir Kotal	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
3099b0088928SVladimir Kotal	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
3100daaffb31Sdp
3101daaffb31Sdp	rm -f $WDIR/$DIR/$F.patch
3102daaffb31Sdp	if [[ -z $rename ]]; then
3103e0e0293aSjmcp		if [ ! -f "$ofile" ]; then
3104daaffb31Sdp			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3105daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3106e0e0293aSjmcp		elif [ ! -f "$nfile" ]; then
3107daaffb31Sdp			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3108daaffb31Sdp			    > $WDIR/$DIR/$F.patch
3109daaffb31Sdp		else
3110daaffb31Sdp			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
3111daaffb31Sdp		fi
3112daaffb31Sdp	else
3113daaffb31Sdp		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
3114daaffb31Sdp		    > $WDIR/$DIR/$F.patch
3115daaffb31Sdp
3116daaffb31Sdp		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
3117daaffb31Sdp		    >> $WDIR/$DIR/$F.patch
3118daaffb31Sdp	fi
3119daaffb31Sdp
3120daaffb31Sdp	#
3121daaffb31Sdp	# Tack the patch we just made onto the accumulated patch for the
3122daaffb31Sdp	# whole wad.
3123daaffb31Sdp	#
3124daaffb31Sdp	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
3125daaffb31Sdp	print " patch\c"
3126daaffb31Sdp
3127daaffb31Sdp	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
3128daaffb31Sdp		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
3129daaffb31Sdp		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
3130daaffb31Sdp		    > $WDIR/$DIR/$F.cdiff.html
31317c478bd9Sstevel@tonic-gate		print " cdiffs\c"
31327c478bd9Sstevel@tonic-gate
3133daaffb31Sdp		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
3134daaffb31Sdp		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
3135daaffb31Sdp		    > $WDIR/$DIR/$F.udiff.html
31367c478bd9Sstevel@tonic-gate		print " udiffs\c"
31377c478bd9Sstevel@tonic-gate
31387c478bd9Sstevel@tonic-gate		if [[ -x $WDIFF ]]; then
3139daaffb31Sdp			$WDIFF -c "$COMM" \
3140daaffb31Sdp			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
3141daaffb31Sdp			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
3142daaffb31Sdp			if [[ $? -eq 0 ]]; then
31437c478bd9Sstevel@tonic-gate				print " wdiffs\c"
3144daaffb31Sdp			else
3145daaffb31Sdp				print " wdiffs[fail]\c"
3146daaffb31Sdp			fi
31477c478bd9Sstevel@tonic-gate		fi
31487c478bd9Sstevel@tonic-gate
3149daaffb31Sdp		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
3150daaffb31Sdp		    > $WDIR/$DIR/$F.sdiff.html
31517c478bd9Sstevel@tonic-gate		print " sdiffs\c"
31527c478bd9Sstevel@tonic-gate		print " frames\c"
31537c478bd9Sstevel@tonic-gate
31547c478bd9Sstevel@tonic-gate		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
3155daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3156daaffb31Sdp	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
3157daaffb31Sdp		# renamed file: may also have differences
3158daaffb31Sdp		difflines $ofile $nfile > $WDIR/$DIR/$F.count
3159daaffb31Sdp	elif [[ -f $nfile ]]; then
31607c478bd9Sstevel@tonic-gate		# new file: count added lines
3161daaffb31Sdp		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
3162daaffb31Sdp	elif [[ -f $ofile ]]; then
31637c478bd9Sstevel@tonic-gate		# old file: count deleted lines
3164daaffb31Sdp		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
31657c478bd9Sstevel@tonic-gate	fi
31667c478bd9Sstevel@tonic-gate
3167daaffb31Sdp	#
31680c108ed9SYuri Pankov	# Check if it's man page, and create plain text, html and raw (ascii)
31690c108ed9SYuri Pankov	# output for the new version, as well as diffs against old version.
31700c108ed9SYuri Pankov	#
31710c108ed9SYuri Pankov	if [[ -f "$nfile" && "$nfile" = *.+([0-9])*([a-zA-Z]) && \
31720c108ed9SYuri Pankov	    -x $MANDOC && -x $COL ]]; then
3173*932a1e13SYuri Pankov		$MANDOC -Tascii $nfile | $COL -b > $nfile.man.txt
31740c108ed9SYuri Pankov		source_to_html txt < $nfile.man.txt > $nfile.man.txt.html
31750c108ed9SYuri Pankov		print " man-txt\c"
31760c108ed9SYuri Pankov		print "$MANCSS" > $WDIR/raw_files/new/$DIR/man.css
31770c108ed9SYuri Pankov		$MANDOC -Thtml -Ostyle=man.css $nfile > $nfile.man.html
31780c108ed9SYuri Pankov		print " man-html\c"
31790c108ed9SYuri Pankov		$MANDOC -Tascii $nfile > $nfile.man.raw
31800c108ed9SYuri Pankov		print " man-raw\c"
31810c108ed9SYuri Pankov		if [[ -f "$ofile" && -z $mv_but_nodiff ]]; then
3182*932a1e13SYuri Pankov			$MANDOC -Tascii $ofile | $COL -b > $ofile.man.txt
31830c108ed9SYuri Pankov			${CDIFFCMD:-diff -bt -C 5} $ofile.man.txt \
31840c108ed9SYuri Pankov			    $nfile.man.txt > $WDIR/$DIR/$F.man.cdiff
31850c108ed9SYuri Pankov			diff_to_html $F $DIR/$F "C" "$COMM" < \
31860c108ed9SYuri Pankov			    $WDIR/$DIR/$F.man.cdiff > \
31870c108ed9SYuri Pankov			    $WDIR/$DIR/$F.man.cdiff.html
31880c108ed9SYuri Pankov			print " man-cdiffs\c"
31890c108ed9SYuri Pankov			${UDIFFCMD:-diff -bt -U 5} $ofile.man.txt \
31900c108ed9SYuri Pankov			    $nfile.man.txt > $WDIR/$DIR/$F.man.udiff
31910c108ed9SYuri Pankov			diff_to_html $F $DIR/$F "U" "$COMM" < \
31920c108ed9SYuri Pankov			    $WDIR/$DIR/$F.man.udiff > \
31930c108ed9SYuri Pankov			    $WDIR/$DIR/$F.man.udiff.html
31940c108ed9SYuri Pankov			print " man-udiffs\c"
31950c108ed9SYuri Pankov			if [[ -x $WDIFF ]]; then
31960c108ed9SYuri Pankov				$WDIFF -c "$COMM" -t "$WNAME Wdiff $DIR/$F" \
31970c108ed9SYuri Pankov				    $ofile.man.txt $nfile.man.txt > \
31980c108ed9SYuri Pankov				    $WDIR/$DIR/$F.man.wdiff.html 2>/dev/null
31990c108ed9SYuri Pankov				if [[ $? -eq 0 ]]; then
32000c108ed9SYuri Pankov					print " man-wdiffs\c"
32010c108ed9SYuri Pankov				else
32020c108ed9SYuri Pankov					print " man-wdiffs[fail]\c"
32030c108ed9SYuri Pankov				fi
32040c108ed9SYuri Pankov			fi
32050c108ed9SYuri Pankov			sdiff_to_html $ofile.man.txt $nfile.man.txt $F.man $DIR \
32060c108ed9SYuri Pankov			    "$COMM" > $WDIR/$DIR/$F.man.sdiff.html
32070c108ed9SYuri Pankov			print " man-sdiffs\c"
32080c108ed9SYuri Pankov			print " man-frames\c"
32090c108ed9SYuri Pankov		fi
32100c108ed9SYuri Pankov		rm -f $ofile.man.txt $nfile.man.txt
32110c108ed9SYuri Pankov		rm -f $WDIR/$DIR/$F.man.cdiff $WDIR/$DIR/$F.man.udiff
32120c108ed9SYuri Pankov	fi
32130c108ed9SYuri Pankov
32140c108ed9SYuri Pankov	#
3215daaffb31Sdp	# Now we generate the postscript for this file.  We generate diffs
3216daaffb31Sdp	# only in the event that there is delta, or the file is new (it seems
3217daaffb31Sdp	# tree-killing to print out the contents of deleted files).
3218daaffb31Sdp	#
3219daaffb31Sdp	if [[ -f $nfile ]]; then
3220daaffb31Sdp		ocr=$ofile
3221daaffb31Sdp		[[ ! -f $ofile ]] && ocr=/dev/null
3222daaffb31Sdp
3223daaffb31Sdp		if [[ -z $mv_but_nodiff ]]; then
3224daaffb31Sdp			textcomm=`getcomments text $P $PP`
322514983201Sdp			if [[ -x $CODEREVIEW ]]; then
322614983201Sdp				$CODEREVIEW -y "$textcomm" \
322714983201Sdp				    -e $ocr $nfile \
322814983201Sdp				    > /tmp/$$.psfile 2>/dev/null &&
322914983201Sdp				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
3230daaffb31Sdp				if [[ $? -eq 0 ]]; then
3231daaffb31Sdp					print " ps\c"
3232daaffb31Sdp				else
3233daaffb31Sdp					print " ps[fail]\c"
3234daaffb31Sdp				fi
3235daaffb31Sdp			fi
3236daaffb31Sdp		fi
323714983201Sdp	fi
3238daaffb31Sdp
3239cdf0c1d5Smjnelson	if [[ -f $ofile ]]; then
3240cdf0c1d5Smjnelson		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
32417c478bd9Sstevel@tonic-gate		print " old\c"
32427c478bd9Sstevel@tonic-gate	fi
32437c478bd9Sstevel@tonic-gate
3244daaffb31Sdp	if [[ -f $nfile ]]; then
3245daaffb31Sdp		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
32467c478bd9Sstevel@tonic-gate		print " new\c"
32477c478bd9Sstevel@tonic-gate	fi
32487c478bd9Sstevel@tonic-gate
3249cdf0c1d5Smjnelson	cd $OWD
3250cdf0c1d5Smjnelson
3251daaffb31Sdp	print
32527c478bd9Sstevel@tonic-gatedone
32537c478bd9Sstevel@tonic-gate
3254daaffb31Sdpframe_nav_js > $WDIR/ancnav.js
32557c478bd9Sstevel@tonic-gateframe_navigation > $WDIR/ancnav.html
3256daaffb31Sdp
325714983201Sdpif [[ ! -f $WDIR/$WNAME.ps ]]; then
325814983201Sdp	print " Generating PDF: Skipped: no output available"
325914983201Sdpelif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
326014983201Sdp	print " Generating PDF: \c"
326114983201Sdp	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
3262daaffb31Sdp	print "Done."
326314983201Sdpelse
326414983201Sdp	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
326514983201Sdpfi
32667c478bd9Sstevel@tonic-gate
3267e0e0293aSjmcp# If we're in OpenSolaris mode and there's a closed dir under $WDIR,
3268e0e0293aSjmcp# delete it - prevent accidental publishing of closed source
3269e0e0293aSjmcp
3270e0e0293aSjmcpif [[ -n "$Oflag" ]]; then
3271ba44d8a2SVladimir Kotal	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
3272e0e0293aSjmcpfi
3273e0e0293aSjmcp
32747c478bd9Sstevel@tonic-gate# Now build the index.html file that contains
32757c478bd9Sstevel@tonic-gate# links to the source files and their diffs.
32767c478bd9Sstevel@tonic-gate
32777c478bd9Sstevel@tonic-gatecd $CWS
32787c478bd9Sstevel@tonic-gate
32797c478bd9Sstevel@tonic-gate# Save total changed lines for Code Inspection.
3280daaffb31Sdpprint "$TOTL" > $WDIR/TotalChangedLines
32817c478bd9Sstevel@tonic-gate
3282daaffb31Sdpprint "     index.html: \c"
32837c478bd9Sstevel@tonic-gateINDEXFILE=$WDIR/index.html
32847c478bd9Sstevel@tonic-gateexec 3<&1			# duplicate stdout to FD3.
32857c478bd9Sstevel@tonic-gateexec 1<&-			# Close stdout.
32867c478bd9Sstevel@tonic-gateexec > $INDEXFILE		# Open stdout to index file.
32877c478bd9Sstevel@tonic-gate
3288daaffb31Sdpprint "$HTML<head>$STDHEAD"
3289daaffb31Sdpprint "<title>$WNAME</title>"
3290daaffb31Sdpprint "</head>"
3291daaffb31Sdpprint "<body id=\"SUNWwebrev\">"
3292daaffb31Sdpprint "<div class=\"summary\">"
3293daaffb31Sdpprint "<h2>Code Review for $WNAME</h2>"
32947c478bd9Sstevel@tonic-gate
3295daaffb31Sdpprint "<table>"
32967c478bd9Sstevel@tonic-gate
3297daaffb31Sdp#
3298cdf0c1d5Smjnelson# Get the preparer's name:
3299daaffb31Sdp#
3300cdf0c1d5Smjnelson# If the SCM detected is Mercurial, and the configuration property
3301cdf0c1d5Smjnelson# ui.username is available, use that, but be careful to properly escape
3302cdf0c1d5Smjnelson# angle brackets (HTML syntax characters) in the email address.
3303cdf0c1d5Smjnelson#
3304cdf0c1d5Smjnelson# Otherwise, use the current userid in the form "John Doe (jdoe)", but
3305cdf0c1d5Smjnelson# to maintain compatibility with passwd(4), we must support '&' substitutions.
3306cdf0c1d5Smjnelson#
3307cdf0c1d5Smjnelsonpreparer=
3308cdf0c1d5Smjnelsonif [[ "$SCM_MODE" == mercurial ]]; then
3309cdf0c1d5Smjnelson	preparer=`hg showconfig ui.username 2>/dev/null`
3310cdf0c1d5Smjnelson	if [[ -n "$preparer" ]]; then
3311cdf0c1d5Smjnelson		preparer="$(echo "$preparer" | html_quote)"
3312cdf0c1d5Smjnelson	fi
3313cdf0c1d5Smjnelsonfi
3314cdf0c1d5Smjnelsonif [[ -z "$preparer" ]]; then
3315cdf0c1d5Smjnelson	preparer=$(
3316cdf0c1d5Smjnelson	    $PERL -e '
3317cdf0c1d5Smjnelson	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
3318cdf0c1d5Smjnelson	        if ($login) {
3319cdf0c1d5Smjnelson	            $gcos =~ s/\&/ucfirst($login)/e;
3320cdf0c1d5Smjnelson	            printf "%s (%s)\n", $gcos, $login;
3321cdf0c1d5Smjnelson	        } else {
3322cdf0c1d5Smjnelson	            printf "(unknown)\n";
3323cdf0c1d5Smjnelson	        }
3324cdf0c1d5Smjnelson	')
3325daaffb31Sdpfi
3326daaffb31Sdp
332748bc00d6SjmcpPREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
332848bc00d6Sjmcpprint "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
33298bcea973SRichard Loweprint "<tr><th>Workspace:</th><td>${PRETTY_CWS:-$CWS}"
3330cdf0c1d5Smjnelsonprint "</td></tr>"
3331daaffb31Sdpprint "<tr><th>Compare against:</th><td>"
3332daaffb31Sdpif [[ -n $parent_webrev ]]; then
3333daaffb31Sdp	print "webrev at $parent_webrev"
3334daaffb31Sdpelse
33358bcea973SRichard Lowe	print "${PRETTY_PWS:-$PWS}"
3336daaffb31Sdpfi
3337daaffb31Sdpprint "</td></tr>"
3338daaffb31Sdpprint "<tr><th>Summary of changes:</th><td>"
3339daaffb31SdpprintCI $TOTL $TINS $TDEL $TMOD $TUNC
3340daaffb31Sdpprint "</td></tr>"
3341daaffb31Sdp
3342daaffb31Sdpif [[ -f $WDIR/$WNAME.patch ]]; then
3343371d72daSLubomir Sedlacik	wpatch_url="$(print $WNAME.patch | url_encode)"
3344daaffb31Sdp	print "<tr><th>Patch of changes:</th><td>"
3345371d72daSLubomir Sedlacik	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
3346daaffb31Sdpfi
3347daaffb31Sdpif [[ -f $WDIR/$WNAME.pdf ]]; then
3348371d72daSLubomir Sedlacik	wpdf_url="$(print $WNAME.pdf | url_encode)"
3349daaffb31Sdp	print "<tr><th>Printable review:</th><td>"
3350371d72daSLubomir Sedlacik	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
3351daaffb31Sdpfi
3352daaffb31Sdp
3353daaffb31Sdpif [[ -n "$iflag" ]]; then
3354daaffb31Sdp	print "<tr><th>Author comments:</th><td><div>"
3355daaffb31Sdp	cat /tmp/$$.include
3356daaffb31Sdp	print "</div></td></tr>"
3357daaffb31Sdpfi
3358daaffb31Sdpprint "</table>"
3359daaffb31Sdpprint "</div>"
3360daaffb31Sdp
3361daaffb31Sdp#
3362daaffb31Sdp# Second pass through the files: generate the rest of the index file
3363daaffb31Sdp#
3364daaffb31Sdpcat $FLIST | while read LINE
33657c478bd9Sstevel@tonic-gatedo
33667c478bd9Sstevel@tonic-gate	set - $LINE
33677c478bd9Sstevel@tonic-gate	P=$1
33687c478bd9Sstevel@tonic-gate
3369daaffb31Sdp	if [[ $# == 2 ]]; then
33707c478bd9Sstevel@tonic-gate		PP=$2
3371cdf0c1d5Smjnelson		oldname="$PP"
33727c478bd9Sstevel@tonic-gate	else
33737c478bd9Sstevel@tonic-gate		PP=$P
3374daaffb31Sdp		oldname=""
3375daaffb31Sdp	fi
3376daaffb31Sdp
3377cdf0c1d5Smjnelson	mv_but_nodiff=
3378cdf0c1d5Smjnelson	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
3379cdf0c1d5Smjnelson	if [[ $? == 0 && -n "$oldname" ]]; then
3380cdf0c1d5Smjnelson		mv_but_nodiff=1
3381cdf0c1d5Smjnelson	fi
3382cdf0c1d5Smjnelson
3383daaffb31Sdp	DIR=${P%/*}
3384daaffb31Sdp	if [[ $DIR == $P ]]; then
3385daaffb31Sdp		DIR="."   # File at root of workspace
33867c478bd9Sstevel@tonic-gate	fi
33877c478bd9Sstevel@tonic-gate
33887c478bd9Sstevel@tonic-gate	# Avoid processing the same file twice.
33897c478bd9Sstevel@tonic-gate	# It's possible for renamed files to
33907c478bd9Sstevel@tonic-gate	# appear twice in the file list
33917c478bd9Sstevel@tonic-gate
33927c478bd9Sstevel@tonic-gate	F=$WDIR/$P
33937c478bd9Sstevel@tonic-gate
3394daaffb31Sdp	print "<p>"
33957c478bd9Sstevel@tonic-gate
33967c478bd9Sstevel@tonic-gate	# If there's a diffs file, make diffs links
33977c478bd9Sstevel@tonic-gate
3398daaffb31Sdp	if [[ -f $F.cdiff.html ]]; then
3399371d72daSLubomir Sedlacik		cdiff_url="$(print $P.cdiff.html | url_encode)"
3400371d72daSLubomir Sedlacik		udiff_url="$(print $P.udiff.html | url_encode)"
34010c108ed9SYuri Pankov		sdiff_url="$(print $P.sdiff.html | url_encode)"
34020c108ed9SYuri Pankov		frames_url="$(print $P.frames.html | url_encode)"
3403371d72daSLubomir Sedlacik		print "<a href=\"$cdiff_url\">Cdiffs</a>"
3404371d72daSLubomir Sedlacik		print "<a href=\"$udiff_url\">Udiffs</a>"
3405daaffb31Sdp		if [[ -f $F.wdiff.html && -x $WDIFF ]]; then
3406371d72daSLubomir Sedlacik			wdiff_url="$(print $P.wdiff.html | url_encode)"
3407371d72daSLubomir Sedlacik			print "<a href=\"$wdiff_url\">Wdiffs</a>"
34087c478bd9Sstevel@tonic-gate		fi
3409371d72daSLubomir Sedlacik		print "<a href=\"$sdiff_url\">Sdiffs</a>"
3410371d72daSLubomir Sedlacik		print "<a href=\"$frames_url\">Frames</a>"
34117c478bd9Sstevel@tonic-gate	else
34120c108ed9SYuri Pankov		print " ------ ------"
3413daaffb31Sdp		if [[ -x $WDIFF ]]; then
34147c478bd9Sstevel@tonic-gate			print " ------"
34157c478bd9Sstevel@tonic-gate		fi
34160c108ed9SYuri Pankov		print " ------ ------"
34177c478bd9Sstevel@tonic-gate	fi
34187c478bd9Sstevel@tonic-gate
34197c478bd9Sstevel@tonic-gate	# If there's an old file, make the link
34207c478bd9Sstevel@tonic-gate
3421daaffb31Sdp	if [[ -f $F-.html ]]; then
3422371d72daSLubomir Sedlacik		oldfile_url="$(print $P-.html | url_encode)"
3423371d72daSLubomir Sedlacik		print "<a href=\"$oldfile_url\">Old</a>"
34247c478bd9Sstevel@tonic-gate	else
3425daaffb31Sdp		print " ---"
34267c478bd9Sstevel@tonic-gate	fi
34277c478bd9Sstevel@tonic-gate
34287c478bd9Sstevel@tonic-gate	# If there's an new file, make the link
34297c478bd9Sstevel@tonic-gate
3430daaffb31Sdp	if [[ -f $F.html ]]; then
3431371d72daSLubomir Sedlacik		newfile_url="$(print $P.html | url_encode)"
3432371d72daSLubomir Sedlacik		print "<a href=\"$newfile_url\">New</a>"
34337c478bd9Sstevel@tonic-gate	else
3434daaffb31Sdp		print " ---"
34357c478bd9Sstevel@tonic-gate	fi
34367c478bd9Sstevel@tonic-gate
3437daaffb31Sdp	if [[ -f $F.patch ]]; then
3438371d72daSLubomir Sedlacik		patch_url="$(print $P.patch | url_encode)"
3439371d72daSLubomir Sedlacik		print "<a href=\"$patch_url\">Patch</a>"
3440daaffb31Sdp	else
3441daaffb31Sdp		print " -----"
3442daaffb31Sdp	fi
3443daaffb31Sdp
3444daaffb31Sdp	if [[ -f $WDIR/raw_files/new/$P ]]; then
3445371d72daSLubomir Sedlacik		rawfiles_url="$(print raw_files/new/$P | url_encode)"
3446371d72daSLubomir Sedlacik		print "<a href=\"$rawfiles_url\">Raw</a>"
3447daaffb31Sdp	else
3448daaffb31Sdp		print " ---"
3449daaffb31Sdp	fi
3450daaffb31Sdp
3451cdf0c1d5Smjnelson	print "<b>$P</b>"
3452cdf0c1d5Smjnelson
3453cdf0c1d5Smjnelson	# For renamed files, clearly state whether or not they are modified
3454e6ccc173SEdward Pilatowicz	if [[ -f "$oldname" ]]; then
3455cdf0c1d5Smjnelson		if [[ -n "$mv_but_nodiff" ]]; then
3456e6ccc173SEdward Pilatowicz			print "<i>(copied from $oldname)</i>"
3457cdf0c1d5Smjnelson		else
3458e6ccc173SEdward Pilatowicz			print "<i>(copied and modified from $oldname)</i>"
3459e6ccc173SEdward Pilatowicz		fi
3460e6ccc173SEdward Pilatowicz	elif [[ -n "$oldname" ]]; then
3461e6ccc173SEdward Pilatowicz		if [[ -n "$mv_but_nodiff" ]]; then
3462e6ccc173SEdward Pilatowicz			print "<i>(renamed from $oldname)</i>"
3463e6ccc173SEdward Pilatowicz		else
3464e6ccc173SEdward Pilatowicz			print "<i>(renamed and modified from $oldname)</i>"
3465cdf0c1d5Smjnelson		fi
3466cdf0c1d5Smjnelson	fi
3467cdf0c1d5Smjnelson
3468cdf0c1d5Smjnelson	# If there's an old file, but no new file, the file was deleted
3469cdf0c1d5Smjnelson	if [[ -f $F-.html && ! -f $F.html ]]; then
3470cdf0c1d5Smjnelson		print " <i>(deleted)</i>"
3471cdf0c1d5Smjnelson	fi
3472daaffb31Sdp
3473e0e0293aSjmcp	# Check for usr/closed and deleted_files/usr/closed
3474daaffb31Sdp	if [ ! -z "$Oflag" ]; then
3475e0e0293aSjmcp		if [[ $P == usr/closed/* || \
3476e0e0293aSjmcp		    $P == deleted_files/usr/closed/* ]]; then
3477daaffb31Sdp			print "&nbsp;&nbsp;<i>Closed source: omitted from" \
3478daaffb31Sdp			    "this review</i>"
3479daaffb31Sdp		fi
3480daaffb31Sdp	fi
3481daaffb31Sdp
34820c108ed9SYuri Pankov	manpage=
34830c108ed9SYuri Pankov	if [[ -f $F.man.cdiff.html || \
34840c108ed9SYuri Pankov	    -f $WDIR/raw_files/new/$P.man.txt.html ]]; then
34850c108ed9SYuri Pankov		manpage=1
34860c108ed9SYuri Pankov		print "<br/>man:"
34870c108ed9SYuri Pankov	fi
34887c478bd9Sstevel@tonic-gate
34890c108ed9SYuri Pankov	if [[ -f $F.man.cdiff.html ]]; then
34900c108ed9SYuri Pankov		mancdiff_url="$(print $P.man.cdiff.html | url_encode)"
34910c108ed9SYuri Pankov		manudiff_url="$(print $P.man.udiff.html | url_encode)"
34920c108ed9SYuri Pankov		mansdiff_url="$(print $P.man.sdiff.html | url_encode)"
34930c108ed9SYuri Pankov		manframes_url="$(print $P.man.frames.html | url_encode)"
34940c108ed9SYuri Pankov		print "<a href=\"$mancdiff_url\">Cdiffs</a>"
34950c108ed9SYuri Pankov		print "<a href=\"$manudiff_url\">Udiffs</a>"
34960c108ed9SYuri Pankov		if [[ -f $F.man.wdiff.html && -x $WDIFF ]]; then
34970c108ed9SYuri Pankov			manwdiff_url="$(print $P.man.wdiff.html | url_encode)"
34980c108ed9SYuri Pankov			print "<a href=\"$manwdiff_url\">Wdiffs</a>"
34990c108ed9SYuri Pankov		fi
35000c108ed9SYuri Pankov		print "<a href=\"$mansdiff_url\">Sdiffs</a>"
35010c108ed9SYuri Pankov		print "<a href=\"$manframes_url\">Frames</a>"
35020c108ed9SYuri Pankov	elif [[ -n $manpage ]]; then
35030c108ed9SYuri Pankov		print " ------ ------"
35040c108ed9SYuri Pankov		if [[ -x $WDIFF ]]; then
35050c108ed9SYuri Pankov			print " ------"
35060c108ed9SYuri Pankov		fi
35070c108ed9SYuri Pankov		print " ------ ------"
35080c108ed9SYuri Pankov	fi
35090c108ed9SYuri Pankov
35100c108ed9SYuri Pankov	if [[ -f $WDIR/raw_files/new/$P.man.txt.html ]]; then
35110c108ed9SYuri Pankov		mantxt_url="$(print raw_files/new/$P.man.txt.html | url_encode)"
35120c108ed9SYuri Pankov		print "<a href=\"$mantxt_url\">TXT</a>"
35130c108ed9SYuri Pankov		manhtml_url="$(print raw_files/new/$P.man.html | url_encode)"
35140c108ed9SYuri Pankov		print "<a href=\"$manhtml_url\">HTML</a>"
35150c108ed9SYuri Pankov		manraw_url="$(print raw_files/new/$P.man.raw | url_encode)"
35160c108ed9SYuri Pankov		print "<a href=\"$manraw_url\">Raw</a>"
35170c108ed9SYuri Pankov	elif [[ -n $manpage ]]; then
35180c108ed9SYuri Pankov		print " --- ---- ---"
35190c108ed9SYuri Pankov	fi
35200c108ed9SYuri Pankov
35210c108ed9SYuri Pankov	print "</p>"
35220c108ed9SYuri Pankov
35230c108ed9SYuri Pankov	# Insert delta comments
3524daaffb31Sdp	print "<blockquote><pre>"
3525daaffb31Sdp	getcomments html $P $PP
3526daaffb31Sdp	print "</pre>"
35277c478bd9Sstevel@tonic-gate
35287c478bd9Sstevel@tonic-gate	# Add additional comments comment
3529daaffb31Sdp	print "<!-- Add comments to explain changes in $P here -->"
35307c478bd9Sstevel@tonic-gate
35317c478bd9Sstevel@tonic-gate	# Add count of changes.
3532daaffb31Sdp	if [[ -f $F.count ]]; then
35337c478bd9Sstevel@tonic-gate	    cat $F.count
35347c478bd9Sstevel@tonic-gate	    rm $F.count
35357c478bd9Sstevel@tonic-gate	fi
3536cdf0c1d5Smjnelson
35373ba097dbSBart Coddens	if [[ $SCM_MODE == "mercurial" ||
3538cdf0c1d5Smjnelson	    $SCM_MODE == "unknown" ]]; then
3539cdf0c1d5Smjnelson		# Include warnings for important file mode situations:
3540cdf0c1d5Smjnelson		# 1) New executable files
3541cdf0c1d5Smjnelson		# 2) Permission changes of any kind
3542cdf0c1d5Smjnelson		# 3) Existing executable files
3543cdf0c1d5Smjnelson		old_mode=
3544cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/old/$PP ]]; then
3545cdf0c1d5Smjnelson			old_mode=`get_file_mode $WDIR/raw_files/old/$PP`
3546cdf0c1d5Smjnelson		fi
3547cdf0c1d5Smjnelson
3548cdf0c1d5Smjnelson		new_mode=
3549cdf0c1d5Smjnelson		if [[ -f $WDIR/raw_files/new/$P ]]; then
3550cdf0c1d5Smjnelson			new_mode=`get_file_mode $WDIR/raw_files/new/$P`
3551cdf0c1d5Smjnelson		fi
3552cdf0c1d5Smjnelson
3553cdf0c1d5Smjnelson		if [[ -z "$old_mode" && "$new_mode" = *[1357]* ]]; then
3554cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3555cdf0c1d5Smjnelson			print "<p>new executable file: mode $new_mode</p>"
3556cdf0c1d5Smjnelson			print "</span>"
3557cdf0c1d5Smjnelson		elif [[ -n "$old_mode" && -n "$new_mode" &&
3558cdf0c1d5Smjnelson		    "$old_mode" != "$new_mode" ]]; then
3559cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3560cdf0c1d5Smjnelson			print "<p>mode change: $old_mode to $new_mode</p>"
3561cdf0c1d5Smjnelson			print "</span>"
3562cdf0c1d5Smjnelson		elif [[ "$new_mode" = *[1357]* ]]; then
3563cdf0c1d5Smjnelson			print "<span class=\"chmod\">"
3564cdf0c1d5Smjnelson			print "<p>executable file: mode $new_mode</p>"
3565cdf0c1d5Smjnelson			print "</span>"
3566cdf0c1d5Smjnelson		fi
3567cdf0c1d5Smjnelson	fi
3568cdf0c1d5Smjnelson
3569daaffb31Sdp	print "</blockquote>"
35707c478bd9Sstevel@tonic-gatedone
35717c478bd9Sstevel@tonic-gate
3572daaffb31Sdpprint
3573daaffb31Sdpprint
3574cac38512Smjnelsonprint "<hr></hr>"
3575daaffb31Sdpprint "<p style=\"font-size: small\">"
35769a70fc3bSMark J. Nelsonprint "This code review page was prepared using <b>$0</b>."
357787a4464eSChris Loveprint "Webrev is maintained by the <a href=\"http://www.illumos.org\">"
357887a4464eSChris Loveprint "illumos</a> project.  The latest version may be obtained"
35797646c8f3SMarcel Telkaprint "<a href=\"http://src.illumos.org/source/xref/illumos-gate/usr/src/tools/scripts/webrev.sh\">here</a>.</p>"
3580daaffb31Sdpprint "</body>"
3581daaffb31Sdpprint "</html>"
35827c478bd9Sstevel@tonic-gate
35837c478bd9Sstevel@tonic-gateexec 1<&-			# Close FD 1.
35847c478bd9Sstevel@tonic-gateexec 1<&3			# dup FD 3 to restore stdout.
35857c478bd9Sstevel@tonic-gateexec 3<&-			# close FD 3.
35867c478bd9Sstevel@tonic-gate
3587daaffb31Sdpprint "Done."
358802d26c39SVladimir Kotal
3589b0088928SVladimir Kotal#
3590ba44d8a2SVladimir Kotal# If remote deletion was specified and fails do not continue.
3591b0088928SVladimir Kotal#
3592ba44d8a2SVladimir Kotalif [[ -n $Dflag ]]; then
3593b0088928SVladimir Kotal	delete_webrev 1 1
3594ba44d8a2SVladimir Kotal	(( $? == 0 )) || exit $?
3595ba44d8a2SVladimir Kotalfi
3596ba44d8a2SVladimir Kotal
359702d26c39SVladimir Kotalif [[ -n $Uflag ]]; then
359802d26c39SVladimir Kotal	upload_webrev
359902d26c39SVladimir Kotal	exit $?
360002d26c39SVladimir Kotalfi
3601