Home | History | Annotate | Download | only in scripts
      1   9196      Mark #!/usr/bin/ksh93 -p
      2      0    stevel #
      3      0    stevel # CDDL HEADER START
      4      0    stevel #
      5      0    stevel # The contents of this file are subject to the terms of the
      6   3252        dp # Common Development and Distribution License (the "License").
      7   3252        dp # You may not use this file except in compliance with the License.
      8      0    stevel #
      9      0    stevel # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10      0    stevel # or http://www.opensolaris.org/os/licensing.
     11      0    stevel # See the License for the specific language governing permissions
     12      0    stevel # and limitations under the License.
     13      0    stevel #
     14      0    stevel # When distributing Covered Code, include this CDDL HEADER in each
     15      0    stevel # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16      0    stevel # If applicable, add the following below this CDDL HEADER, with the
     17      0    stevel # fields enclosed by brackets "[]" replaced with your own identifying
     18      0    stevel # information: Portions Copyright [yyyy] [name of copyright owner]
     19      0    stevel #
     20      0    stevel # CDDL HEADER END
     21      0    stevel #
     22   7298      Mark 
     23      0    stevel #
     24   9011   Lubomir # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     25      0    stevel # Use is subject to license terms.
     26   7078  mjnelson #
     27   7078  mjnelson 
     28      0    stevel #
     29   3252        dp # This script takes a file list and a workspace and builds a set of html files
     30   3252        dp # suitable for doing a code review of source changes via a web page.
     31   3252        dp # Documentation is available via the manual page, webrev.1, or just
     32   3252        dp # type 'webrev -h'.
     33      0    stevel #
     34   3252        dp # Acknowledgements to contributors to webrev are listed in the webrev(1)
     35   3252        dp # man page.
     36      0    stevel #
     37      0    stevel 
     38      0    stevel REMOVED_COLOR=brown
     39      0    stevel CHANGED_COLOR=blue
     40      0    stevel NEW_COLOR=blue
     41      0    stevel 
     42   3252        dp HTML='<?xml version="1.0"?>
     43   3252        dp <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     44   3252        dp     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     45   3252        dp <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
     46   3252        dp 
     47   3252        dp FRAMEHTML='<?xml version="1.0"?>
     48   3252        dp <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
     49   3252        dp     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
     50   3252        dp <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n'
     51   3252        dp 
     52   6922  mjnelson STDHEAD='<meta http-equiv="cache-control" content="no-cache"></meta>
     53   6922  mjnelson <meta http-equiv="Pragma" content="no-cache"></meta>
     54   6922  mjnelson <meta http-equiv="Expires" content="-1"></meta>
     55   3252        dp <!--
     56   3252        dp    Note to customizers: the body of the webrev is IDed as SUNWwebrev
     57   3252        dp    to allow easy overriding by users of webrev via the userContent.css
     58   3252        dp    mechanism available in some browsers.
     59   3252        dp 
     60   3252        dp    For example, to have all "removed" information be red instead of
     61   3252        dp    brown, set a rule in your userContent.css file like:
     62   3252        dp 
     63   3252        dp        body#SUNWwebrev span.removed { color: red ! important; }
     64   3252        dp -->
     65   3252        dp <style type="text/css" media="screen">
     66   3252        dp body {
     67   3252        dp     background-color: #eeeeee;
     68   3252        dp }
     69   3252        dp hr {
     70   3252        dp     border: none 0;
     71   3252        dp     border-top: 1px solid #aaa;
     72   3252        dp     height: 1px;
     73   3252        dp }
     74   3252        dp div.summary {
     75   3252        dp     font-size: .8em;
     76   3252        dp     border-bottom: 1px solid #aaa;
     77   3252        dp     padding-left: 1em;
     78   3252        dp     padding-right: 1em;
     79   3252        dp }
     80   3252        dp div.summary h2 {
     81   3252        dp     margin-bottom: 0.3em;
     82   3252        dp }
     83   3252        dp div.summary table th {
     84   3252        dp     text-align: right;
     85   3252        dp     vertical-align: top;
     86   3252        dp     white-space: nowrap;
     87   3252        dp }
     88   3252        dp span.lineschanged {
     89   3252        dp     font-size: 0.7em;
     90   3252        dp }
     91   3252        dp span.oldmarker {
     92   3252        dp     color: red;
     93   3252        dp     font-size: large;
     94   3252        dp     font-weight: bold;
     95   3252        dp }
     96   3252        dp span.newmarker {
     97   3252        dp     color: green;
     98   3252        dp     font-size: large;
     99   3252        dp     font-weight: bold;
    100   3252        dp }
    101   3252        dp span.removed {
    102   3252        dp     color: brown;
    103   3252        dp }
    104   3252        dp span.changed {
    105   3252        dp     color: blue;
    106   3252        dp }
    107   3252        dp span.new {
    108   3252        dp     color: blue;
    109   3252        dp     font-weight: bold;
    110   3252        dp }
    111   7078  mjnelson span.chmod {
    112   7078  mjnelson     font-size: 0.7em;
    113   7078  mjnelson     color: #db7800;
    114   7078  mjnelson }
    115   3252        dp a.print { font-size: x-small; }
    116   3252        dp a:hover { background-color: #ffcc99; }
    117   3252        dp </style>
    118   3252        dp 
    119   3252        dp <style type="text/css" media="print">
    120   3252        dp pre { font-size: 0.8em; font-family: courier, monospace; }
    121   3252        dp span.removed { color: #444; font-style: italic }
    122   3252        dp span.changed { font-weight: bold; }
    123   3252        dp span.new { font-weight: bold; }
    124   3252        dp span.newmarker { font-size: 1.2em; font-weight: bold; }
    125   3252        dp span.oldmarker { font-size: 1.2em; font-weight: bold; }
    126   3252        dp a.print {display: none}
    127   3252        dp hr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
    128   3252        dp </style>
    129   3252        dp '
    130   3252        dp 
    131   3252        dp #
    132   3252        dp # UDiffs need a slightly different CSS rule for 'new' items (we don't
    133   3252        dp # want them to be bolded as we do in cdiffs or sdiffs).
    134   3252        dp #
    135   3252        dp UDIFFCSS='
    136   3252        dp <style type="text/css" media="screen">
    137   3252        dp span.new {
    138   3252        dp     color: blue;
    139   3252        dp     font-weight: normal;
    140   3252        dp }
    141   3252        dp </style>
    142   3252        dp '
    143   8018  Vladimir 
    144   9079  Vladimir #
    145   9079  Vladimir # Display remote target with prefix and trailing slash.
    146   9079  Vladimir #
    147   9079  Vladimir function print_upload_header
    148   9079  Vladimir {
    149   9079  Vladimir 	typeset -r prefix=$1
    150   9079  Vladimir 	typeset display_target
    151   9079  Vladimir 
    152   9079  Vladimir 	if [[ -z $tflag ]]; then
    153   9079  Vladimir 		display_target=${prefix}${remote_target}
    154   9079  Vladimir 	else
    155   9079  Vladimir 		display_target=${remote_target}
    156   9079  Vladimir 	fi
    157   9079  Vladimir 
    158   9079  Vladimir 	if [[ ${display_target} != */ ]]; then
    159   9079  Vladimir 		display_target=${display_target}/
    160   9079  Vladimir 	fi
    161   9079  Vladimir 
    162   9079  Vladimir 	print "      Upload to: ${display_target}\n" \
    163   9079  Vladimir 	    "     Uploading: \c"
    164   9079  Vladimir }
    165   9079  Vladimir 
    166   9079  Vladimir #
    167   8018  Vladimir # Upload the webrev via rsync. Return 0 on success, 1 on error.
    168   9079  Vladimir #
    169   8365  Vladimir function rsync_upload
    170   8018  Vladimir {
    171   9079  Vladimir 	if (( $# != 2 )); then
    172   9079  Vladimir 		print "\nERROR: rsync_upload: wrong usage ($#)"
    173   9079  Vladimir 		exit 1
    174   9079  Vladimir 	fi
    175   9079  Vladimir 
    176   9079  Vladimir 	typeset -r dst=$1
    177   9079  Vladimir 	integer -r print_err_msg=$2
    178   9079  Vladimir 
    179   9079  Vladimir 	print_upload_header ${rsync_prefix}
    180   9079  Vladimir 	print "rsync ... \c"
    181   9503  Vladimir 	typeset -r err_msg=$( $MKTEMP /tmp/rsync_err.XXXXXX )
    182   9079  Vladimir 	if [[ -z $err_msg ]]; then
    183   9079  Vladimir 		print "\nERROR: rsync_upload: cannot create temporary file"
    184   9079  Vladimir 		return 1
    185   9079  Vladimir 	fi
    186   9079  Vladimir 	#
    187   9079  Vladimir 	# The source directory must end with a slash in order to copy just
    188   9079  Vladimir 	# directory contents, not the whole directory.
    189   9079  Vladimir 	#
    190   9079  Vladimir 	typeset src_dir=$WDIR
    191   9079  Vladimir 	if [[ ${src_dir} != */ ]]; then
    192   9079  Vladimir 		src_dir=${src_dir}/
    193   9079  Vladimir 	fi
    194   9079  Vladimir 	$RSYNC -r -q ${src_dir} $dst 2>$err_msg
    195   9079  Vladimir 	if (( $? != 0 )); then
    196   9079  Vladimir 		if (( ${print_err_msg} > 0 )); then
    197   9079  Vladimir 			print "Failed.\nERROR: rsync failed"
    198   9079  Vladimir 			print "src dir: '${src_dir}'\ndst dir: '$dst'"
    199   9079  Vladimir 			print "error messages:"
    200   9079  Vladimir 			$SED 's/^/> /' $err_msg
    201   9079  Vladimir 			rm -f $err_msg
    202   9079  Vladimir 		fi
    203   8018  Vladimir 		return 1
    204   8018  Vladimir 	fi
    205   8018  Vladimir 
    206   9079  Vladimir 	rm -f $err_msg
    207   8018  Vladimir 	print "Done."
    208   8018  Vladimir 	return 0
    209   8018  Vladimir }
    210   8018  Vladimir 
    211   9079  Vladimir #
    212   9079  Vladimir # Create directories on remote host using SFTP. Return 0 on success,
    213   9079  Vladimir # 1 on failure.
    214   9079  Vladimir #
    215   9079  Vladimir function remote_mkdirs
    216   9079  Vladimir {
    217   9079  Vladimir 	typeset -r dir_spec=$1
    218   9079  Vladimir 
    219   9079  Vladimir 	#
    220   9079  Vladimir 	# If the supplied path is absolute we assume all directories are
    221   9079  Vladimir 	# created, otherwise try to create all directories in the path
    222   9079  Vladimir 	# except the last one which will be created by scp.
    223   9079  Vladimir 	#
    224   9079  Vladimir 	if [[ "${dir_spec}" == */* && "${dir_spec}" != /* ]]; then
    225   9079  Vladimir 		print "mkdirs \c"
    226   9079  Vladimir 		#
    227   9079  Vladimir 		# Remove the last directory from directory specification.
    228   9079  Vladimir 		#
    229   9079  Vladimir 		typeset -r dirs_mk=${dir_spec%/*}
    230   9503  Vladimir 		typeset -r batch_file_mkdir=$( $MKTEMP \
    231   9503  Vladimir 		    /tmp/webrev_mkdir.XXXXXX )
    232   9079  Vladimir 		if [[ -z $batch_file_mkdir ]]; then
    233   9079  Vladimir 			print "\nERROR: remote_mkdirs:" \
    234   9079  Vladimir 			    "cannot create temporary file for batch file"
    235   9079  Vladimir 			return 1
    236   9079  Vladimir 		fi
    237   9079  Vladimir                 OLDIFS=$IFS
    238   9079  Vladimir                 IFS=/
    239   9079  Vladimir 		typeset dir
    240   9079  Vladimir                 for dir in ${dirs_mk}; do
    241   9079  Vladimir 			#
    242   9079  Vladimir 			# Use the '-' prefix to ignore mkdir errors in order
    243   9079  Vladimir 			# to avoid an error in case the directory already
    244   9079  Vladimir 			# exists. We check the directory with chdir to be sure
    245   9079  Vladimir 			# there is one.
    246   9079  Vladimir 			#
    247   9079  Vladimir                         print -- "-mkdir ${dir}" >> ${batch_file_mkdir}
    248   9079  Vladimir                         print "chdir ${dir}" >> ${batch_file_mkdir}
    249   9079  Vladimir                 done
    250   9079  Vladimir                 IFS=$OLDIFS
    251   9503  Vladimir 		typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
    252   9079  Vladimir 		if [[ -z ${sftp_err_msg} ]]; then
    253   9079  Vladimir 			print "\nERROR: remote_mkdirs:" \
    254   9079  Vladimir 			    "cannot create temporary file for error messages"
    255   9079  Vladimir 			return 1
    256   9079  Vladimir 		fi
    257   9079  Vladimir 		$SFTP -b ${batch_file_mkdir} ${host_spec} 2>${sftp_err_msg} 1>&2
    258   9079  Vladimir 		if (( $? != 0 )); then
    259   9079  Vladimir 			print "\nERROR: failed to create remote directories"
    260   9079  Vladimir 			print "error messages:"
    261   9079  Vladimir 			$SED 's/^/> /' ${sftp_err_msg}
    262   9079  Vladimir 			rm -f ${sftp_err_msg} ${batch_file_mkdir}
    263   9079  Vladimir 			return 1
    264   9079  Vladimir 		fi
    265   9079  Vladimir 		rm -f ${sftp_err_msg} ${batch_file_mkdir}
    266   9079  Vladimir 	fi
    267   9079  Vladimir 
    268   9079  Vladimir 	return 0
    269   9079  Vladimir }
    270   9079  Vladimir 
    271   9079  Vladimir #
    272   8018  Vladimir # Upload the webrev via SSH. Return 0 on success, 1 on error.
    273   9079  Vladimir #
    274   8365  Vladimir function ssh_upload
    275   8018  Vladimir {
    276   8018  Vladimir 	if (( $# != 1 )); then
    277   9079  Vladimir 		print "\nERROR: ssh_upload: wrong number of arguments"
    278   9079  Vladimir 		exit 1
    279   8018  Vladimir 	fi
    280   8018  Vladimir 
    281   8018  Vladimir 	typeset dst=$1
    282   8018  Vladimir 	typeset -r host_spec=${dst%%:*}
    283   8365  Vladimir 	typeset -r dir_spec=${dst#*:}
    284   8018  Vladimir 
    285   9079  Vladimir 	#
    286   9079  Vladimir 	# Display the upload information before calling delete_webrev
    287   9079  Vladimir 	# because it will also print its progress.
    288   9079  Vladimir 	#
    289   9079  Vladimir 	print_upload_header ${ssh_prefix}
    290   9079  Vladimir 
    291   9079  Vladimir 	#
    292   9079  Vladimir 	# If the deletion was explicitly requested there is no need
    293   9079  Vladimir 	# to perform it again.
    294   9079  Vladimir 	#
    295   8365  Vladimir 	if [[ -z $Dflag ]]; then
    296   9079  Vladimir 		#
    297   9079  Vladimir 		# We do not care about return value because this might be
    298   9079  Vladimir 		# the first time this directory is uploaded.
    299   9079  Vladimir 		#
    300   8365  Vladimir 		delete_webrev 0
    301   8018  Vladimir 	fi
    302   8018  Vladimir 
    303   9079  Vladimir 	#
    304   9079  Vladimir 	# Create remote directories. Any error reporting will be done
    305   9079  Vladimir 	# in remote_mkdirs function.
    306   9079  Vladimir 	#
    307   9079  Vladimir 	remote_mkdirs ${dir_spec}
    308   8018  Vladimir 	if (( $? != 0 )); then
    309   8018  Vladimir 		return 1
    310   8018  Vladimir 	fi
    311   8018  Vladimir 
    312   9079  Vladimir 	print "upload ... \c"
    313   9503  Vladimir 	typeset -r scp_err_msg=$( $MKTEMP /tmp/scp_err.XXXXXX )
    314   9079  Vladimir 	if [[ -z ${scp_err_msg} ]]; then
    315   9079  Vladimir 		print "\nERROR: ssh_upload:" \
    316   9079  Vladimir 		    "cannot create temporary file for error messages"
    317   9079  Vladimir 		return 1
    318   9079  Vladimir 	fi
    319   9079  Vladimir 	$SCP -q -C -B -o PreferredAuthentications=publickey -r \
    320   9079  Vladimir 		$WDIR $dst 2>${scp_err_msg}
    321   9079  Vladimir 	if (( $? != 0 )); then
    322   9079  Vladimir 		print "Failed.\nERROR: scp failed"
    323   9079  Vladimir 		print "src dir: '$WDIR'\ndst dir: '$dst'"
    324   9079  Vladimir 		print "error messages:"
    325   9079  Vladimir 		$SED 's/^/> /' ${scp_err_msg}
    326   9079  Vladimir 		rm -f ${scp_err_msg}
    327   9079  Vladimir 		return 1
    328   9079  Vladimir 	fi
    329   9079  Vladimir 
    330   9079  Vladimir 	rm -f ${scp_err_msg}
    331   8018  Vladimir 	print "Done."
    332   8018  Vladimir 	return 0
    333   8018  Vladimir }
    334   8018  Vladimir 
    335   8018  Vladimir #
    336   8365  Vladimir # Delete webrev at remote site. Return 0 on success, 1 or exit code from sftp
    337   9079  Vladimir # on failure. If first argument is 1 then perform the check of sftp return
    338   9079  Vladimir # value otherwise ignore it. If second argument is present it means this run
    339   9079  Vladimir # only performs deletion.
    340   8365  Vladimir #
    341   8365  Vladimir function delete_webrev
    342   8365  Vladimir {
    343   9079  Vladimir 	if (( $# < 1 )); then
    344   9079  Vladimir 		print "delete_webrev: wrong number of arguments"
    345   9079  Vladimir 		exit 1
    346   8365  Vladimir 	fi
    347   8365  Vladimir 
    348   9079  Vladimir 	integer -r check=$1
    349   9079  Vladimir 	integer delete_only=0
    350   9079  Vladimir 	if (( $# == 2 )); then
    351   9079  Vladimir 		delete_only=1
    352   9079  Vladimir 	fi
    353   9079  Vladimir 
    354   9079  Vladimir 	#
    355   8365  Vladimir 	# Strip the transport specification part of remote target first.
    356   9079  Vladimir 	#
    357   8365  Vladimir 	typeset -r stripped_target=${remote_target##*://}
    358   8365  Vladimir 	typeset -r host_spec=${stripped_target%%:*}
    359   8365  Vladimir 	typeset -r dir_spec=${stripped_target#*:}
    360   8365  Vladimir 	typeset dir_rm
    361   8365  Vladimir 
    362   9079  Vladimir 	#
    363   8365  Vladimir 	# Do not accept an absolute path.
    364   9079  Vladimir 	#
    365   8365  Vladimir 	if [[ ${dir_spec} == /* ]]; then
    366   8365  Vladimir 		return 1
    367   8365  Vladimir 	fi
    368   8365  Vladimir 
    369   9079  Vladimir 	#
    370   8365  Vladimir 	# Strip the ending slash.
    371   9079  Vladimir 	#
    372   8365  Vladimir 	if [[ ${dir_spec} == */ ]]; then
    373   8365  Vladimir 		dir_rm=${dir_spec%%/}
    374   8365  Vladimir 	else
    375   8365  Vladimir 		dir_rm=${dir_spec}
    376   8365  Vladimir 	fi
    377   8365  Vladimir 
    378   9079  Vladimir 	if (( ${delete_only} > 0 )); then
    379   9079  Vladimir 		print "       Removing: \c"
    380   9079  Vladimir 	else
    381   9079  Vladimir 		print "rmdir \c"
    382   9079  Vladimir 	fi
    383   8365  Vladimir 	if [[ -z "$dir_rm" ]]; then
    384   9079  Vladimir 		print "\nERROR: empty directory for removal"
    385   8365  Vladimir 		return 1
    386   8365  Vladimir 	fi
    387   8365  Vladimir 
    388   9079  Vladimir 	#
    389   8365  Vladimir 	# Prepare batch file.
    390   9079  Vladimir 	#
    391   9503  Vladimir 	typeset -r batch_file_rm=$( $MKTEMP /tmp/webrev_remove.XXXXXX )
    392   8365  Vladimir 	if [[ -z $batch_file_rm ]]; then
    393   9079  Vladimir 		print "\nERROR: delete_webrev: cannot create temporary file"
    394   8365  Vladimir 		return 1
    395   8365  Vladimir 	fi
    396   8365  Vladimir 	print "rename $dir_rm $TRASH_DIR/removed.$$" > $batch_file_rm
    397   8365  Vladimir 
    398   9079  Vladimir 	#
    399   8365  Vladimir 	# Perform remote deletion and remove the batch file.
    400   9079  Vladimir 	#
    401   9503  Vladimir 	typeset -r sftp_err_msg=$( $MKTEMP /tmp/webrev_scp_err.XXXXXX )
    402   9079  Vladimir 	if [[ -z ${sftp_err_msg} ]]; then
    403   9079  Vladimir 		print "\nERROR: delete_webrev:" \
    404   9079  Vladimir 		    "cannot create temporary file for error messages"
    405   9079  Vladimir 		return 1
    406   9079  Vladimir 	fi
    407   9079  Vladimir 	$SFTP -b $batch_file_rm $host_spec 2>${sftp_err_msg} 1>&2
    408   8365  Vladimir 	integer -r ret=$?
    409   8365  Vladimir 	rm -f $batch_file_rm
    410   8365  Vladimir 	if (( $ret != 0 && $check > 0 )); then
    411   9079  Vladimir 		print "Failed.\nERROR: failed to remove remote directories"
    412   9079  Vladimir 		print "error messages:"
    413   9079  Vladimir 		$SED 's/^/> /' ${sftp_err_msg}
    414   9079  Vladimir 		rm -f ${sftp_err_msg}
    415   8365  Vladimir 		return $ret
    416   8365  Vladimir 	fi
    417   9079  Vladimir 	rm -f ${sftp_err_msg}
    418   9079  Vladimir 	if (( ${delete_only} > 0 )); then
    419   9079  Vladimir 		print "Done."
    420   9079  Vladimir 	fi
    421   8365  Vladimir 
    422   8365  Vladimir 	return 0
    423   8365  Vladimir }
    424   8365  Vladimir 
    425   8365  Vladimir #
    426   8018  Vladimir # Upload webrev to remote site
    427   8018  Vladimir #
    428   8365  Vladimir function upload_webrev
    429   8018  Vladimir {
    430   9079  Vladimir 	integer ret
    431   8018  Vladimir 
    432   8018  Vladimir 	if [[ ! -d "$WDIR" ]]; then
    433   9079  Vladimir 		print "\nERROR: webrev directory '$WDIR' does not exist"
    434   8018  Vladimir 		return 1
    435   8018  Vladimir 	fi
    436   8018  Vladimir 
    437   9079  Vladimir 	#
    438   8018  Vladimir 	# Perform a late check to make sure we do not upload closed source
    439   8018  Vladimir 	# to remote target when -n is used. If the user used custom remote
    440   8018  Vladimir 	# target he probably knows what he is doing.
    441   9079  Vladimir 	#
    442   8018  Vladimir 	if [[ -n $nflag && -z $tflag ]]; then
    443   8365  Vladimir 		$FIND $WDIR -type d -name closed \
    444   8018  Vladimir 			| $GREP closed >/dev/null
    445   8018  Vladimir 		if (( $? == 0 )); then
    446   9079  Vladimir 			print "\nERROR: directory '$WDIR' contains" \
    447   9079  Vladimir 			    "\"closed\" directory"
    448   8018  Vladimir 			return 1
    449   8018  Vladimir 		fi
    450   8018  Vladimir 	fi
    451   8018  Vladimir 
    452   9079  Vladimir 
    453   9079  Vladimir 	#
    454   9079  Vladimir 	# We have the URI for remote destination now so let's start the upload.
    455   9079  Vladimir 	#
    456   8018  Vladimir 	if [[ -n $tflag ]]; then
    457   8018  Vladimir 		if [[ "${remote_target}" == ${rsync_prefix}?* ]]; then
    458   9079  Vladimir 			rsync_upload ${remote_target##$rsync_prefix} 1
    459   9079  Vladimir 			ret=$?
    460   9079  Vladimir 			return $ret
    461   8018  Vladimir 		elif [[ "${remote_target}" == ${ssh_prefix}?* ]]; then
    462   8018  Vladimir 			ssh_upload ${remote_target##$ssh_prefix}
    463   9079  Vladimir 			ret=$?
    464   9079  Vladimir 			return $ret
    465   8018  Vladimir 		fi
    466   8018  Vladimir 	else
    467   9079  Vladimir 		#
    468   9079  Vladimir 		# Try rsync first and fallback to SSH in case it fails.
    469   9079  Vladimir 		#
    470   9079  Vladimir 		rsync_upload ${remote_target} 0
    471   9079  Vladimir 		ret=$?
    472   9079  Vladimir 		if (( $ret != 0 )); then
    473   9079  Vladimir 			print "Failed. (falling back to SSH)"
    474   8365  Vladimir 			ssh_upload ${remote_target}
    475   9079  Vladimir 			ret=$?
    476   8018  Vladimir 		fi
    477   9079  Vladimir 		return $ret
    478   8018  Vladimir 	fi
    479   9011   Lubomir }
    480   9011   Lubomir 
    481   9011   Lubomir #
    482   9011   Lubomir # input_cmd | url_encode | output_cmd
    483   9011   Lubomir #
    484   9011   Lubomir # URL-encode (percent-encode) reserved characters as defined in RFC 3986.
    485   9011   Lubomir #
    486   9011   Lubomir # Reserved characters are: :/?#[]@!$&'()*+,;=
    487   9011   Lubomir #
    488   9011   Lubomir # While not a reserved character itself, percent '%' is reserved by definition
    489   9011   Lubomir # so encode it first to avoid recursive transformation, and skip '/' which is
    490   9011   Lubomir # a path delimiter.
    491   9011   Lubomir #
    492   9561  Vladimir # The quotation character is deliberately not escaped in order to make
    493   9561  Vladimir # the substitution work with GNU sed.
    494   9561  Vladimir #
    495   9011   Lubomir function url_encode
    496   9011   Lubomir {
    497   9079  Vladimir 	$SED -e "s|%|%25|g" -e "s|:|%3A|g" -e "s|\&|%26|g" \
    498   9011   Lubomir 	    -e "s|?|%3F|g" -e "s|#|%23|g" -e "s|\[|%5B|g" \
    499   9011   Lubomir 	    -e "s|*|%2A|g" -e "s|@|%40|g" -e "s|\!|%21|g" \
    500   9011   Lubomir 	    -e "s|=|%3D|g" -e "s|;|%3B|g" -e "s|\]|%5D|g" \
    501   9561  Vladimir 	    -e "s|(|%28|g" -e "s|)|%29|g" -e "s|'|%27|g" \
    502   9011   Lubomir 	    -e "s|+|%2B|g" -e "s|\,|%2C|g" -e "s|\\\$|%24|g"
    503   8018  Vladimir }
    504   3252        dp 
    505   3252        dp #
    506   3252        dp # input_cmd | html_quote | output_cmd
    507   3252        dp # or
    508   3252        dp # html_quote filename | output_cmd
    509      0    stevel #
    510      0    stevel # Make a piece of source code safe for display in an HTML <pre> block.
    511      0    stevel #
    512      0    stevel html_quote()
    513      0    stevel {
    514   9079  Vladimir 	$SED -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
    515      0    stevel }
    516      0    stevel 
    517   3252        dp #
    518   9193      Mark # input_cmd | its2url | output_cmd
    519   3252        dp #
    520   9193      Mark # Scan for information tracking system references and insert <a> links to the
    521   9193      Mark # relevant databases.
    522   3252        dp #
    523   9193      Mark its2url()
    524      0    stevel {
    525   9193      Mark 	$SED -f ${its_sed_script}
    526   3252        dp }
    527   3252        dp 
    528      0    stevel #
    529   3252        dp # strip_unchanged <infile> | output_cmd
    530      0    stevel #
    531   3252        dp # Removes chunks of sdiff documents that have not changed. This makes it
    532   3252        dp # easier for a code reviewer to find the bits that have changed.
    533      0    stevel #
    534   3252        dp # Deleted lines of text are replaced by a horizontal rule. Some
    535   3252        dp # identical lines are retained before and after the changed lines to
    536   3252        dp # provide some context.  The number of these lines is controlled by the
    537   7078  mjnelson # variable C in the $AWK script below.
    538   3252        dp #
    539   3252        dp # The script detects changed lines as any line that has a "<span class="
    540   3252        dp # string embedded (unchanged lines have no particular class and are not
    541   3252        dp # part of a <span>).  Blank lines (without a sequence number) are also
    542   3252        dp # detected since they flag lines that have been inserted or deleted.
    543   3252        dp #
    544   3252        dp strip_unchanged()
    545   3252        dp {
    546   7078  mjnelson 	$AWK '
    547   3252        dp 	BEGIN	{ C = c = 20 }
    548   7078  mjnelson 	NF == 0 || /<span class="/ {
    549   3252        dp 		if (c > C) {
    550   3252        dp 			c -= C
    551   3252        dp 			inx = 0
    552   3252        dp 			if (c > C) {
    553   6922  mjnelson 				print "\n</pre><hr></hr><pre>"
    554   3252        dp 				inx = c % C
    555   3252        dp 				c = C
    556   3252        dp 			}
    557   3252        dp 
    558   3252        dp 			for (i = 0; i < c; i++)
    559   3252        dp 				print ln[(inx + i) % C]
    560   3252        dp 		}
    561   3252        dp 		c = 0;
    562   3252        dp 		print
    563   3252        dp 		next
    564   3252        dp 	}
    565   3252        dp 	{	if (c >= C) {
    566   3252        dp 			ln[c % C] = $0
    567   3252        dp 			c++;
    568   3252        dp 			next;
    569   3252        dp 		}
    570   3252        dp 		c++;
    571   3252        dp 		print
    572   3252        dp 	}
    573   6922  mjnelson 	END	{ if (c > (C * 2)) print "\n</pre><hr></hr>" }
    574   3252        dp 
    575   3252        dp 	' $1
    576   3252        dp }
    577   3252        dp 
    578   3252        dp #
    579   3252        dp # sdiff_to_html
    580   3252        dp #
    581   3252        dp # This function takes two files as arguments, obtains their diff, and
    582   3252        dp # processes the diff output to present the files as an HTML document with
    583   3252        dp # the files displayed side-by-side, differences shown in color.  It also
    584   3252        dp # takes a delta comment, rendered as an HTML snippet, as the third
    585   3252        dp # argument.  The function takes two files as arguments, then the name of
    586   3252        dp # file, the path, and the comment.  The HTML will be delivered on stdout,
    587   3252        dp # e.g.
    588   3252        dp #
    589   3252        dp #   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
    590   3252        dp #         new/usr/src/tools/scripts/webrev.sh \
    591   3252        dp #         webrev.sh usr/src/tools/scripts \
    592   3252        dp #         '<a href="http://monaco.sfbay.sun.com/detail.jsp?cr=1234567">
    593   3252        dp #          1234567</a> my bugid' > <file>.html
    594   3252        dp #
    595   3252        dp # framed_sdiff() is then called which creates $2.frames.html
    596   3252        dp # in the webrev tree.
    597   3252        dp #
    598   3252        dp # FYI: This function is rather unusual in its use of awk.  The initial
    599   3252        dp # diff run produces conventional diff output showing changed lines mixed
    600   3252        dp # with editing codes.  The changed lines are ignored - we're interested in
    601   3252        dp # the editing codes, e.g.
    602      0    stevel #
    603      0    stevel #      8c8
    604      0    stevel #      57a61
    605      0    stevel #      63c66,76
    606      0    stevel #      68,93d80
    607      0    stevel #      106d90
    608      0    stevel #      108,110d91
    609      0    stevel #
    610   3252        dp #  These editing codes are parsed by the awk script and used to generate
    611   3252        dp #  another awk script that generates HTML, e.g the above lines would turn
    612   3252        dp #  into something like this:
    613      0    stevel #
    614      0    stevel #      BEGIN { printf "<pre>\n" }
    615      0    stevel #      function sp(n) {for (i=0;i<n;i++)printf "\n"}
    616   3252        dp #      function wl(n) {printf "<font color=%s>%4d %s </font>\n", n, NR, $0}
    617      0    stevel #      NR==8           {wl("#7A7ADD");next}
    618      0    stevel #      NR==54          {wl("#7A7ADD");sp(3);next}
    619      0    stevel #      NR==56          {wl("#7A7ADD");next}
    620      0    stevel #      NR==57          {wl("black");printf "\n"; next}
    621      0    stevel #        :               :
    622      0    stevel #
    623   3252        dp #  This script is then run on the original source file to generate the
    624   3252        dp #  HTML that corresponds to the source file.
    625      0    stevel #
    626   3252        dp #  The two HTML files are then combined into a single piece of HTML that
    627   3252        dp #  uses an HTML table construct to present the files side by side.  You'll
    628   3252        dp #  notice that the changes are color-coded:
    629      0    stevel #
    630      0    stevel #   black     - unchanged lines
    631      0    stevel #   blue      - changed lines
    632      0    stevel #   bold blue - new lines
    633      0    stevel #   brown     - deleted lines
    634      0    stevel #
    635   3252        dp #  Blank lines are inserted in each file to keep unchanged lines in sync
    636   3252        dp #  (side-by-side).  This format is familiar to users of sdiff(1) or
    637   3252        dp #  Teamware's filemerge tool.
    638   3252        dp #
    639   3252        dp sdiff_to_html()
    640   3252        dp {
    641   3252        dp 	diff -b $1 $2 > /tmp/$$.diffs
    642      0    stevel 
    643   3252        dp 	TNAME=$3
    644   3252        dp 	TPATH=$4
    645   3252        dp 	COMMENT=$5
    646      0    stevel 
    647   3252        dp 	#
    648   3252        dp 	#  Now we have the diffs, generate the HTML for the old file.
    649   3252        dp 	#
    650   7078  mjnelson 	$AWK '
    651   3252        dp 	BEGIN	{
    652   3252        dp 		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
    653   3252        dp 		printf "function removed() "
    654   3252        dp 		printf "{printf \"<span class=\\\"removed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
    655   3252        dp 		printf "function changed() "
    656   3252        dp 		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
    657   3252        dp 		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
    658   3252        dp }
    659   3252        dp 	/^</	{next}
    660   3252        dp 	/^>/	{next}
    661   3252        dp 	/^---/	{next}
    662      0    stevel 
    663   3252        dp 	{
    664      0    stevel 	split($1, a, /[cad]/) ;
    665      0    stevel 	if (index($1, "a")) {
    666      0    stevel 		if (a[1] == 0) {
    667      0    stevel 			n = split(a[2], r, /,/);
    668      0    stevel 			if (n == 1)
    669      0    stevel 				printf "BEGIN\t\t{sp(1)}\n"
    670      0    stevel 			else
    671      0    stevel 				printf "BEGIN\t\t{sp(%d)}\n",\
    672      0    stevel 				(r[2] - r[1]) + 1
    673      0    stevel 			next
    674      0    stevel 		}
    675      0    stevel 
    676      0    stevel 		printf "NR==%s\t\t{", a[1]
    677      0    stevel 		n = split(a[2], r, /,/);
    678      0    stevel 		s = r[1];
    679      0    stevel 		if (n == 1)
    680      0    stevel 			printf "bl();printf \"\\n\"; next}\n"
    681      0    stevel 		else {
    682      0    stevel 			n = r[2] - r[1]
    683      0    stevel 			printf "bl();sp(%d);next}\n",\
    684      0    stevel 			(r[2] - r[1]) + 1
    685      0    stevel 		}
    686   3252        dp 		next
    687      0    stevel 	}
    688      0    stevel 	if (index($1, "d")) {
    689      0    stevel 		n = split(a[1], r, /,/);
    690      0    stevel 		n1 = r[1]
    691      0    stevel 		n2 = r[2]
    692      0    stevel 		if (n == 1)
    693   3252        dp 			printf "NR==%s\t\t{removed(); next}\n" , n1
    694      0    stevel 		else
    695   3252        dp 			printf "NR==%s,NR==%s\t{removed(); next}\n" , n1, n2
    696   3252        dp 		next
    697      0    stevel 	}
    698      0    stevel 	if (index($1, "c")) {
    699      0    stevel 		n = split(a[1], r, /,/);
    700      0    stevel 		n1 = r[1]
    701      0    stevel 		n2 = r[2]
    702      0    stevel 		final = n2
    703      0    stevel 		d1 = 0
    704      0    stevel 		if (n == 1)
    705   3252        dp 			printf "NR==%s\t\t{changed();" , n1
    706      0    stevel 		else {
    707      0    stevel 			d1 = n2 - n1
    708   3252        dp 			printf "NR==%s,NR==%s\t{changed();" , n1, n2
    709      0    stevel 		}
    710      0    stevel 		m = split(a[2], r, /,/);
    711      0    stevel 		n1 = r[1]
    712      0    stevel 		n2 = r[2]
    713      0    stevel 		if (m > 1) {
    714      0    stevel 			d2  = n2 - n1
    715      0    stevel 			if (d2 > d1) {
    716      0    stevel 				if (n > 1) printf "if (NR==%d)", final
    717      0    stevel 				printf "sp(%d);", d2 - d1
    718      0    stevel 			}
    719      0    stevel 		}
    720      0    stevel 		printf "next}\n" ;
    721   3252        dp 
    722   3252        dp 		next
    723      0    stevel 	}
    724   3252        dp 	}
    725      0    stevel 
    726   3252        dp 	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
    727   3252        dp 	' /tmp/$$.diffs > /tmp/$$.file1
    728      0    stevel 
    729   3252        dp 	#
    730   3252        dp 	#  Now generate the HTML for the new file
    731   3252        dp 	#
    732   7078  mjnelson 	$AWK '
    733   3252        dp 	BEGIN	{
    734   3252        dp 		printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
    735   3252        dp 		printf "function new() "
    736   3252        dp 		printf "{printf \"<span class=\\\"new\\\">%%4d %%s</span>\\n\", NR, $0}\n"
    737   3252        dp 		printf "function changed() "
    738   3252        dp 		printf "{printf \"<span class=\\\"changed\\\">%%4d %%s</span>\\n\", NR, $0}\n"
    739   3252        dp 		printf "function bl() {printf \"%%4d %%s\\n\", NR, $0}\n"
    740   3252        dp 	}
    741      0    stevel 
    742   3252        dp 	/^</	{next}
    743   3252        dp 	/^>/	{next}
    744   3252        dp 	/^---/	{next}
    745   3252        dp 
    746   3252        dp 	{
    747      0    stevel 	split($1, a, /[cad]/) ;
    748      0    stevel 	if (index($1, "d")) {
    749      0    stevel 		if (a[2] == 0) {
    750      0    stevel 			n = split(a[1], r, /,/);
    751      0    stevel 			if (n == 1)
    752      0    stevel 				printf "BEGIN\t\t{sp(1)}\n"
    753      0    stevel 			else
    754      0    stevel 				printf "BEGIN\t\t{sp(%d)}\n",\
    755      0    stevel 				(r[2] - r[1]) + 1
    756      0    stevel 			next
    757      0    stevel 		}
    758      0    stevel 
    759      0    stevel 		printf "NR==%s\t\t{", a[2]
    760      0    stevel 		n = split(a[1], r, /,/);
    761      0    stevel 		s = r[1];
    762      0    stevel 		if (n == 1)
    763      0    stevel 			printf "bl();printf \"\\n\"; next}\n"
    764      0    stevel 		else {
    765      0    stevel 			n = r[2] - r[1]
    766      0    stevel 			printf "bl();sp(%d);next}\n",\
    767      0    stevel 			(r[2] - r[1]) + 1
    768      0    stevel 		}
    769   3252        dp 		next
    770      0    stevel 	}
    771      0    stevel 	if (index($1, "a")) {
    772      0    stevel 		n = split(a[2], r, /,/);
    773      0    stevel 		n1 = r[1]
    774      0    stevel 		n2 = r[2]
    775      0    stevel 		if (n == 1)
    776   3252        dp 			printf "NR==%s\t\t{new() ; next}\n" , n1
    777      0    stevel 		else
    778   3252        dp 			printf "NR==%s,NR==%s\t{new() ; next}\n" , n1, n2
    779   3252        dp 		next
    780      0    stevel 	}
    781      0    stevel 	if (index($1, "c")) {
    782      0    stevel 		n = split(a[2], r, /,/);
    783      0    stevel 		n1 = r[1]
    784      0    stevel 		n2 = r[2]
    785      0    stevel 		final = n2
    786      0    stevel 		d2 = 0;
    787      0    stevel 		if (n == 1) {
    788      0    stevel 			final = n1
    789   3252        dp 			printf "NR==%s\t\t{changed();" , n1
    790      0    stevel 		} else {
    791      0    stevel 			d2 = n2 - n1
    792   3252        dp 			printf "NR==%s,NR==%s\t{changed();" , n1, n2
    793      0    stevel 		}
    794      0    stevel 		m = split(a[1], r, /,/);
    795      0    stevel 		n1 = r[1]
    796      0    stevel 		n2 = r[2]
    797      0    stevel 		if (m > 1) {
    798      0    stevel 			d1  = n2 - n1
    799      0    stevel 			if (d1 > d2) {
    800      0    stevel 				if (n > 1) printf "if (NR==%d)", final
    801      0    stevel 				printf "sp(%d);", d1 - d2
    802      0    stevel 			}
    803      0    stevel 		}
    804      0    stevel 		printf "next}\n" ;
    805   3252        dp 		next
    806      0    stevel 	}
    807   3252        dp 	}
    808   3252        dp 	END	{ printf "{printf \"%%4d %%s\\n\", NR, $0 }\n" }
    809   3252        dp 	' /tmp/$$.diffs > /tmp/$$.file2
    810      0    stevel 
    811   3252        dp 	#
    812   7078  mjnelson 	# Post-process the HTML files by running them back through $AWK
    813   3252        dp 	#
    814   7078  mjnelson 	html_quote < $1 | $AWK -f /tmp/$$.file1 > /tmp/$$.file1.html
    815      0    stevel 
    816   7078  mjnelson 	html_quote < $2 | $AWK -f /tmp/$$.file2 > /tmp/$$.file2.html
    817      0    stevel 
    818   3252        dp 	#
    819   3252        dp 	# Now combine into a valid HTML file and side-by-side into a table
    820   3252        dp 	#
    821   3252        dp 	print "$HTML<head>$STDHEAD"
    822   7078  mjnelson 	print "<title>$WNAME Sdiff $TPATH/$TNAME</title>"
    823   3252        dp 	print "</head><body id=\"SUNWwebrev\">"
    824   3252        dp         print "<a class=\"print\" href=\"javascript:print()\">Print this page</a>"
    825   3252        dp 	print "<pre>$COMMENT</pre>\n"
    826   3252        dp 	print "<table><tr valign=\"top\">"
    827   3252        dp 	print "<td><pre>"
    828      0    stevel 
    829   3252        dp 	strip_unchanged /tmp/$$.file1.html
    830      0    stevel 
    831   3252        dp 	print "</pre></td><td><pre>"
    832      0    stevel 
    833   3252        dp 	strip_unchanged /tmp/$$.file2.html
    834      0    stevel 
    835   3252        dp 	print "</pre></td>"
    836   3252        dp 	print "</tr></table>"
    837   3252        dp 	print "</body></html>"
    838      0    stevel 
    839   3252        dp 	framed_sdiff $TNAME $TPATH /tmp/$$.file1.html /tmp/$$.file2.html \
    840   3252        dp 	    "$COMMENT"
    841      0    stevel }
    842      0    stevel 
    843      0    stevel 
    844   3252        dp #
    845   3252        dp # framed_sdiff <filename> <filepath> <lhsfile> <rhsfile> <comment>
    846   3252        dp #
    847   3252        dp # Expects lefthand and righthand side html files created by sdiff_to_html.
    848   3252        dp # We use insert_anchors() to augment those with HTML navigation anchors,
    849   3252        dp # and then emit the main frame.  Content is placed into:
    850   3252        dp #
    851   3252        dp #    $WDIR/DIR/$TNAME.lhs.html
    852   3252        dp #    $WDIR/DIR/$TNAME.rhs.html
    853   3252        dp #    $WDIR/DIR/$TNAME.frames.html
    854   3252        dp #
    855   3252        dp # NOTE: We rely on standard usage of $WDIR and $DIR.
    856   3252        dp #
    857      0    stevel function framed_sdiff
    858      0    stevel {
    859   3252        dp 	typeset TNAME=$1
    860   3252        dp 	typeset TPATH=$2
    861   3252        dp 	typeset lhsfile=$3
    862   3252        dp 	typeset rhsfile=$4
    863   3252        dp 	typeset comments=$5
    864   3252        dp 	typeset RTOP
    865   3252        dp 
    866   3252        dp 	# Enable html files to access WDIR via a relative path.
    867   3252        dp 	RTOP=$(relative_dir $TPATH $WDIR)
    868   3252        dp 
    869   3252        dp 	# Make the rhs/lhs files and output the frameset file.
    870   3252        dp 	print "$HTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.lhs.html
    871   3252        dp 
    872   3252        dp 	cat >> $WDIR/$DIR/$TNAME.lhs.html <<-EOF
    873   9191      Mark 	    <script type="text/javascript" src="${RTOP}ancnav.js"></script>
    874   3252        dp 	    </head>
    875   3252        dp 	    <body id="SUNWwebrev" onkeypress="keypress(event);">
    876   6922  mjnelson 	    <a name="0"></a>
    877   6922  mjnelson 	    <pre>$comments</pre><hr></hr>
    878   3252        dp 	EOF
    879   3252        dp 
    880   3252        dp 	cp $WDIR/$DIR/$TNAME.lhs.html $WDIR/$DIR/$TNAME.rhs.html
    881   3252        dp 
    882   3252        dp 	insert_anchors $lhsfile >> $WDIR/$DIR/$TNAME.lhs.html
    883   3252        dp 	insert_anchors $rhsfile >> $WDIR/$DIR/$TNAME.rhs.html
    884   3252        dp 
    885   3252        dp 	close='</body></html>'
    886   3252        dp 
    887   3252        dp 	print $close >> $WDIR/$DIR/$TNAME.lhs.html
    888   3252        dp 	print $close >> $WDIR/$DIR/$TNAME.rhs.html
    889   3252        dp 
    890   3252        dp 	print "$FRAMEHTML<head>$STDHEAD" > $WDIR/$DIR/$TNAME.frames.html
    891   3252        dp 	print "<title>$WNAME Framed-Sdiff " \
    892   3252        dp 	    "$TPATH/$TNAME</title> </head>" >> $WDIR/$DIR/$TNAME.frames.html
    893   3252        dp 	cat >> $WDIR/$DIR/$TNAME.frames.html <<-EOF
    894   3252        dp 	  <frameset rows="*,60">
    895   3252        dp 	    <frameset cols="50%,50%">
    896   6922  mjnelson 	      <frame src="$TNAME.lhs.html" scrolling="auto" name="lhs"></frame>
    897   6922  mjnelson 	      <frame src="$TNAME.rhs.html" scrolling="auto" name="rhs"></frame>
    898   3252        dp 	    </frameset>
    899   9191      Mark 	  <frame src="${RTOP}ancnav.html" scrolling="no" marginwidth="0"
    900   6922  mjnelson 	   marginheight="0" name="nav"></frame>
    901   3252        dp 	  <noframes>
    902   3252        dp             <body id="SUNWwebrev">
    903   3252        dp 	      Alas 'frames' webrev requires that your browser supports frames
    904   3252        dp 	      and has the feature enabled.
    905   3252        dp             </body>
    906   3252        dp 	  </noframes>
    907   3252        dp 	  </frameset>
    908      0    stevel 	</html>
    909      0    stevel 	EOF
    910      0    stevel }
    911      0    stevel 
    912      0    stevel 
    913   3252        dp #
    914   3252        dp # fix_postscript
    915   3252        dp #
    916   3252        dp # Merge codereview output files to a single conforming postscript file, by:
    917  10789    Edward #	- removing all extraneous headers/trailers
    918   3252        dp #	- making the page numbers right
    919   3252        dp #	- removing pages devoid of contents which confuse some
    920   3252        dp #	  postscript readers.
    921   3252        dp #
    922   3252        dp # From Casper.
    923   3252        dp #
    924   3252        dp function fix_postscript
    925      0    stevel {
    926   3252        dp 	infile=$1
    927      0    stevel 
    928   3252        dp 	cat > /tmp/$$.crmerge.pl << \EOF
    929      0    stevel 
    930   3252        dp 	print scalar(<>);		# %!PS-Adobe---
    931   3252        dp 	print "%%Orientation: Landscape\n";
    932   3252        dp 
    933   3252        dp 	$pno = 0;
    934   3252        dp 	$doprint = 1;
    935   3252        dp 
    936   3252        dp 	$page = "";
    937   3252        dp 
    938   3252        dp 	while (<>) {
    939   3252        dp 		next if (/^%%Pages:\s*\d+/);
    940   3252        dp 
    941   3252        dp 		if (/^%%Page:/) {
    942   3252        dp 			if ($pno == 0 || $page =~ /\)S/) {
    943   3252        dp 				# Header or single page containing text
    944   3252        dp 				print "%%Page: ? $pno\n" if ($pno > 0);
    945   3252        dp 				print $page;
    946   3252        dp 				$pno++;
    947   3252        dp 			} else {
    948   3252        dp 				# Empty page, skip it.
    949   3252        dp 			}
    950   3252        dp 			$page = "";
    951   3252        dp 			$doprint = 1;
    952   3252        dp 			next;
    953      0    stevel 		}
    954      0    stevel 
    955   3252        dp 		# Skip from %%Trailer of one document to Endprolog
    956   3252        dp 		# %%Page of the next
    957   3252        dp 		$doprint = 0 if (/^%%Trailer/);
    958   3252        dp 		$page .= $_ if ($doprint);
    959      0    stevel 	}
    960   3252        dp 
    961   3252        dp 	if ($page =~ /\)S/) {
    962   3252        dp 		print "%%Page: ? $pno\n";
    963   3252        dp 		print $page;
    964   3252        dp 	} else {
    965   3252        dp 		$pno--;
    966   3252        dp 	}
    967   3252        dp 	print "%%Trailer\n%%Pages: $pno\n";
    968   3252        dp EOF
    969   3252        dp 
    970   3295        dp 	$PERL /tmp/$$.crmerge.pl < $infile
    971      0    stevel }
    972      0    stevel 
    973      0    stevel 
    974   3252        dp #
    975   3252        dp # input_cmd | insert_anchors | output_cmd
    976   3252        dp #
    977      0    stevel # Flag blocks of difference with sequentially numbered invisible
    978   3252        dp # anchors.  These are used to drive the frames version of the
    979      0    stevel # sdiffs output.
    980      0    stevel #
    981      0    stevel # NOTE: Anchor zero flags the top of the file irrespective of changes,
    982      0    stevel # an additional anchor is also appended to flag the bottom.
    983      0    stevel #
    984   3252        dp # The script detects changed lines as any line that has a "<span
    985   3252        dp # class=" string embedded (unchanged lines have no class set and are
    986   3252        dp # not part of a <span>.  Blank lines (without a sequence number)
    987      0    stevel # are also detected since they flag lines that have been inserted or
    988      0    stevel # deleted.
    989      0    stevel #
    990   3252        dp function insert_anchors
    991   3252        dp {
    992   7078  mjnelson 	$AWK '
    993   3252        dp 	function ia() {
    994   3252        dp 		printf "<a name=\"%d\" id=\"anc%d\"></a>", anc, anc++;
    995   3252        dp 	}
    996      0    stevel 
    997   3252        dp 	BEGIN {
    998   3252        dp 		anc=1;
    999   3252        dp 		inblock=1;
   1000   3252        dp 		printf "<pre>\n";
   1001   3252        dp 	}
   1002   3252        dp 	NF == 0 || /^<span class=/ {
   1003   3252        dp 		if (inblock == 0) {
   1004   3252        dp 			ia();
   1005   3252        dp 			inblock=1;
   1006   3252        dp 		}
   1007   3252        dp 		print;
   1008   3252        dp 		next;
   1009   3252        dp 	}
   1010   3252        dp 	{
   1011   3252        dp 		inblock=0;
   1012   3252        dp 		print;
   1013   3252        dp 	}
   1014   3252        dp 	END {
   1015   3252        dp 		ia();
   1016      0    stevel 
   1017   3252        dp 		printf "<b style=\"font-size: large; color: red\">";
   1018   3252        dp 		printf "--- EOF ---</b>"
   1019  10789    Edward 		for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
   1020   3252        dp 		printf "</pre>"
   1021   3252        dp 		printf "<form name=\"eof\">";
   1022   6922  mjnelson 		printf "<input name=\"value\" value=\"%d\" " \
   1023   6922  mjnelson 		    "type=\"hidden\"></input>", anc - 1;
   1024   3252        dp 		printf "</form>";
   1025      0    stevel 	}
   1026   3252        dp 	' $1
   1027      0    stevel }
   1028      0    stevel 
   1029      0    stevel 
   1030   3252        dp #
   1031   3252        dp # relative_dir
   1032   3252        dp #
   1033   3252        dp # Print a relative return path from $1 to $2.  For example if
   1034   3252        dp # $1=/tmp/myreview/raw_files/usr/src/tools/scripts and $2=/tmp/myreview,
   1035   3252        dp # this function would print "../../../../".
   1036   3252        dp #
   1037   3252        dp # In the event that $1 is not in $2 a warning is printed to stderr,
   1038   3252        dp # and $2 is returned-- the result of this is that the resulting webrev
   1039   3252        dp # is not relocatable.
   1040   3252        dp #
   1041   3252        dp function relative_dir
   1042      0    stevel {
   1043   9191      Mark         typeset cur="${1##$2?(/)}"
   1044   3252        dp 
   1045   9191      Mark         #
   1046   9191      Mark         # If the first path was specified absolutely, and it does
   1047   9191      Mark         # not start with the second path, it's an error.
   1048   9191      Mark         #
   1049   9193      Mark         if [[ "$cur" = "/${1#/}" ]]; then
   1050   9191      Mark                 # Should never happen.
   1051   9191      Mark                 print -u2 "\nWARNING: relative_dir: \"$1\" not relative "
   1052   9191      Mark                 print -u2 "to \"$2\".  Check input paths.  Framed webrev "
   1053   9191      Mark                 print -u2 "will not be relocatable!"
   1054   9191      Mark                 print $2
   1055   9191      Mark                 return
   1056   9191      Mark         fi
   1057   9191      Mark 
   1058   9191      Mark 	#
   1059   9191      Mark 	# This is kind of ugly.  The sed script will do the following:
   1060   9191      Mark 	#
   1061   9191      Mark 	# 1. Strip off a leading "." or "./": this is important to get
   1062   9191      Mark 	#    the correct arcnav links for files in $WDIR.
   1063  10789    Edward 	# 2. Strip off a trailing "/": this is not strictly necessary,
   1064   9191      Mark 	#    but is kind of nice, since it doesn't end up in "//" at
   1065   9191      Mark 	#    the end of a relative path.
   1066   9191      Mark 	# 3. Replace all remaining sequences of non-"/" with "..": the
   1067   9191      Mark 	#    assumption here is that each dirname represents another
   1068   9191      Mark 	#    level of relative separation.
   1069   9191      Mark 	# 4. Append a trailing "/" only for non-empty paths: this way
   1070   9191      Mark 	#    the caller doesn't need to duplicate this logic, and does
   1071   9191      Mark 	#    not end up using $RTOP/file for files in $WDIR.
   1072   9191      Mark 	#
   1073   9193      Mark 	print $cur | $SED -e '{
   1074   9193      Mark 		s:^\./*::
   1075   9193      Mark 		s:/$::
   1076   9193      Mark 		s:[^/][^/]*:..:g
   1077   9193      Mark 		s:^\(..*\)$:\1/:
   1078   9193      Mark 	}'
   1079      0    stevel }
   1080      0    stevel 
   1081   3252        dp #
   1082   3252        dp # frame_nav_js
   1083   3252        dp #
   1084   3252        dp # Emit javascript for frame navigation
   1085   3252        dp #
   1086   3252        dp function frame_nav_js
   1087      0    stevel {
   1088      0    stevel cat << \EOF
   1089      0    stevel var myInt;
   1090      0    stevel var scrolling=0;
   1091   3252        dp var sfactor = 3;
   1092      0    stevel var scount=10;
   1093      0    stevel 
   1094      0    stevel function scrollByPix() {
   1095      0    stevel 	if (scount<=0) {
   1096      0    stevel 		sfactor*=1.2;
   1097      0    stevel 		scount=10;
   1098      0    stevel 	}
   1099      0    stevel 	parent.lhs.scrollBy(0,sfactor);
   1100      0    stevel 	parent.rhs.scrollBy(0,sfactor);
   1101      0    stevel 	scount--;
   1102      0    stevel }
   1103      0    stevel 
   1104   3252        dp function scrollToAnc(num) {
   1105   3252        dp 
   1106   3252        dp 	// Update the value of the anchor in the form which we use as
   1107   3252        dp 	// storage for this value.  setAncValue() will take care of
   1108   3252        dp 	// correcting for overflow and underflow of the value and return
   1109   3252        dp 	// us the new value.
   1110   3252        dp 	num = setAncValue(num);
   1111   3252        dp 
   1112   3252        dp 	// Set location and scroll back a little to expose previous
   1113   3252        dp 	// lines.
   1114   3252        dp 	//
   1115   3252        dp 	// Note that this could be improved: it is possible although
   1116   3252        dp 	// complex to compute the x and y position of an anchor, and to
   1117   3252        dp 	// scroll to that location directly.
   1118   3252        dp 	//
   1119      0    stevel 	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
   1120      0    stevel 	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
   1121   3252        dp 
   1122      0    stevel 	parent.lhs.scrollBy(0,-30);
   1123      0    stevel 	parent.rhs.scrollBy(0,-30);
   1124   3252        dp }
   1125   3252        dp 
   1126   3252        dp function getAncValue()
   1127   3252        dp {
   1128   3252        dp 	return (parseInt(parent.nav.document.diff.real.value));
   1129   3252        dp }
   1130   3252        dp 
   1131   3252        dp function setAncValue(val)
   1132   3252        dp {
   1133   3252        dp 	if (val <= 0) {
   1134   3252        dp 		val = 0;
   1135   3252        dp 		parent.nav.document.diff.real.value = val;
   1136   3252        dp 		parent.nav.document.diff.display.value = "BOF";
   1137   3252        dp 		return (val);
   1138   3252        dp 	}
   1139   3252        dp 
   1140   3252        dp 	//
   1141   3252        dp 	// The way we compute the max anchor value is to stash it
   1142   3252        dp 	// inline in the left and right hand side pages-- it's the same
   1143   3252        dp 	// on each side, so we pluck from the left.
   1144   3252        dp 	//
   1145   3252        dp 	maxval = parent.lhs.document.eof.value.value;
   1146   3252        dp 	if (val < maxval) {
   1147   3252        dp 		parent.nav.document.diff.real.value = val;
   1148   3252        dp 		parent.nav.document.diff.display.value = val.toString();
   1149   3252        dp 		return (val);
   1150   3252        dp 	}
   1151   3252        dp 
   1152   3252        dp 	// this must be: val >= maxval
   1153   3252        dp 	val = maxval;
   1154   3252        dp 	parent.nav.document.diff.real.value = val;
   1155   3252        dp 	parent.nav.document.diff.display.value = "EOF";
   1156   3252        dp 	return (val);
   1157      0    stevel }
   1158      0    stevel 
   1159      0    stevel function stopScroll() {
   1160      0    stevel 	if (scrolling==1) {
   1161      0    stevel 		clearInterval(myInt);
   1162      0    stevel 		scrolling=0;
   1163      0    stevel 	}
   1164      0    stevel }
   1165      0    stevel 
   1166      0    stevel function startScroll() {
   1167      0    stevel 	stopScroll();
   1168      0    stevel 	scrolling=1;
   1169      0    stevel 	myInt=setInterval("scrollByPix()",10);
   1170      0    stevel }
   1171      0    stevel 
   1172   3252        dp function handlePress(b) {
   1173   3252        dp 
   1174      0    stevel 	switch (b) {
   1175      0    stevel 	    case 1 :
   1176   3252        dp 		scrollToAnc(-1);
   1177      0    stevel 		break;
   1178      0    stevel 	    case 2 :
   1179   3252        dp 		scrollToAnc(getAncValue() - 1);
   1180      0    stevel 		break;
   1181      0    stevel 	    case 3 :
   1182      0    stevel 		sfactor=-3;
   1183      0    stevel 		startScroll();
   1184      0    stevel 		break;
   1185      0    stevel 	    case 4 :
   1186      0    stevel 		sfactor=3;
   1187      0    stevel 		startScroll();
   1188      0    stevel 		break;
   1189      0    stevel 	    case 5 :
   1190   3252        dp 		scrollToAnc(getAncValue() + 1);
   1191      0    stevel 		break;
   1192      0    stevel 	    case 6 :
   1193   3252        dp 		scrollToAnc(999999);
   1194      0    stevel 		break;
   1195      0    stevel 	}
   1196      0    stevel }
   1197      0    stevel 
   1198      0    stevel function handleRelease(b) {
   1199      0    stevel 	stopScroll();
   1200      0    stevel }
   1201      0    stevel 
   1202   3252        dp function keypress(ev) {
   1203   3252        dp 	var keynum;
   1204   3252        dp 	var keychar;
   1205   3252        dp 
   1206   3252        dp 	if (window.event) { // IE
   1207   3252        dp 		keynum = ev.keyCode;
   1208   3252        dp 	} else if (ev.which) { // non-IE
   1209   3252        dp 		keynum = ev.which;
   1210      0    stevel 	}
   1211   3252        dp 
   1212   3252        dp 	keychar = String.fromCharCode(keynum);
   1213   3252        dp 
   1214   3252        dp 	if (keychar == "k") {
   1215   3252        dp 		handlePress(2);
   1216   3252        dp 		return (0);
   1217   3252        dp 	} else if (keychar == "j" || keychar == " ") {
   1218   3252        dp 		handlePress(5);
   1219   3252        dp 		return (0);
   1220   3252        dp 	}
   1221   3252        dp 	return (1);
   1222      0    stevel }
   1223      0    stevel 
   1224   3252        dp function ValidateDiffNum(){
   1225   3252        dp 	val = parent.nav.document.diff.display.value;
   1226   3252        dp 	if (val == "EOF") {
   1227   3252        dp 		scrollToAnc(999999);
   1228   3252        dp 		return;
   1229   3252        dp 	}
   1230   3252        dp 
   1231   3252        dp 	if (val == "BOF") {
   1232   3252        dp 		scrollToAnc(0);
   1233   3252        dp 		return;
   1234   3252        dp 	}
   1235   3252        dp 
   1236   3252        dp         i=parseInt(val);
   1237   3252        dp         if (isNaN(i)) {
   1238   3252        dp                 parent.nav.document.diff.display.value = getAncValue();
   1239   3252        dp         } else {
   1240   3252        dp                 scrollToAnc(i);
   1241   3252        dp         }
   1242   3252        dp         return false;
   1243   3252        dp }
   1244   3252        dp 
   1245   3252        dp EOF
   1246   3252        dp }
   1247   3252        dp 
   1248   3252        dp #
   1249   3252        dp # frame_navigation
   1250   3252        dp #
   1251   3252        dp # Output anchor navigation file for framed sdiffs.
   1252   3252        dp #
   1253   3252        dp function frame_navigation
   1254   3252        dp {
   1255   3252        dp 	print "$HTML<head>$STDHEAD"
   1256   3252        dp 
   1257   3252        dp 	cat << \EOF
   1258   3252        dp <title>Anchor Navigation</title>
   1259   3252        dp <meta http-equiv="Content-Script-Type" content="text/javascript">
   1260   3252        dp <meta http-equiv="Content-Type" content="text/html">
   1261   3252        dp 
   1262   3252        dp <style type="text/css">
   1263   3252        dp     div.button td { padding-left: 5px; padding-right: 5px;
   1264   3252        dp 		    background-color: #eee; text-align: center;
   1265   3252        dp 		    border: 1px #444 outset; cursor: pointer; }
   1266   3252        dp     div.button a { font-weight: bold; color: black }
   1267   3252        dp     div.button td:hover { background: #ffcc99; }
   1268   3252        dp </style>
   1269   3252        dp EOF
   1270   3252        dp 
   1271   6922  mjnelson 	print "<script type=\"text/javascript\" src=\"ancnav.js\"></script>"
   1272   3252        dp 
   1273   3252        dp 	cat << \EOF
   1274   3252        dp </head>
   1275   3252        dp <body id="SUNWwebrev" bgcolor="#eeeeee" onload="document.diff.real.focus();"
   1276   3252        dp 	onkeypress="keypress(event);">
   1277      0    stevel     <noscript lang="javascript">
   1278      0    stevel       <center>
   1279   6922  mjnelson 	<p><big>Framed Navigation controls require Javascript</big><br></br>
   1280      0    stevel 	Either this browser is incompatable or javascript is not enabled</p>
   1281      0    stevel       </center>
   1282      0    stevel     </noscript>
   1283      0    stevel     <table width="100%" border="0" align="center">
   1284   3252        dp 	<tr>
   1285   3252        dp           <td valign="middle" width="25%">Diff navigation:
   1286   3252        dp           Use 'j' and 'k' for next and previous diffs; or use buttons
   1287   3252        dp           at right</td>
   1288   3252        dp 	  <td align="center" valign="top" width="50%">
   1289      0    stevel 	    <div class="button">
   1290   3252        dp 	      <table border="0" align="center">
   1291   3252        dp                   <tr>
   1292   3252        dp 		    <td>
   1293      0    stevel 		      <a onMouseDown="handlePress(1);return true;"
   1294      0    stevel 			 onMouseUp="handleRelease(1);return true;"
   1295      0    stevel 			 onMouseOut="handleRelease(1);return true;"
   1296      0    stevel 			 onClick="return false;"
   1297      0    stevel 			 title="Go to Beginning Of file">BOF</a></td>
   1298   3252        dp 		    <td>
   1299      0    stevel 		      <a onMouseDown="handlePress(3);return true;"
   1300      0    stevel 			 onMouseUp="handleRelease(3);return true;"
   1301      0    stevel 			 onMouseOut="handleRelease(3);return true;"
   1302      0    stevel 			 title="Scroll Up: Press and Hold to accelerate"
   1303   3252        dp 			 onClick="return false;">Scroll Up</a></td>
   1304   3252        dp 		    <td>
   1305      0    stevel 		      <a onMouseDown="handlePress(2);return true;"
   1306      0    stevel 			 onMouseUp="handleRelease(2);return true;"
   1307   3252        dp 			 onMouseOut="handleRelease(2);return true;"
   1308      0    stevel 			 title="Go to previous Diff"
   1309      0    stevel 			 onClick="return false;">Prev Diff</a>
   1310      0    stevel 		    </td></tr>
   1311   3252        dp 
   1312      0    stevel 		  <tr>
   1313   3252        dp 		    <td>
   1314   3252        dp 		      <a onMouseDown="handlePress(6);return true;"
   1315   3252        dp 			 onMouseUp="handleRelease(6);return true;"
   1316   3252        dp 			 onMouseOut="handleRelease(6);return true;"
   1317      0    stevel 			 onClick="return false;"
   1318      0    stevel 			 title="Go to End Of File">EOF</a></td>
   1319   3252        dp 		    <td>
   1320   3252        dp 		      <a onMouseDown="handlePress(4);return true;"
   1321   3252        dp 			 onMouseUp="handleRelease(4);return true;"
   1322   3252        dp 			 onMouseOut="handleRelease(4);return true;"
   1323      0    stevel 			 title="Scroll Down: Press and Hold to accelerate"
   1324   3252        dp 			 onClick="return false;">Scroll Down</a></td>
   1325   3252        dp 		    <td>
   1326   3252        dp 		      <a onMouseDown="handlePress(5);return true;"
   1327   3252        dp 			 onMouseUp="handleRelease(5);return true;"
   1328   3252        dp 			 onMouseOut="handleRelease(5);return true;"
   1329      0    stevel 			 title="Go to next Diff"
   1330      0    stevel 			 onClick="return false;">Next Diff</a></td>
   1331   3252        dp 		  </tr>
   1332   3252        dp               </table>
   1333   3252        dp 	    </div>
   1334   3252        dp 	  </td>
   1335      0    stevel 	  <th valign="middle" width="25%">
   1336   3252        dp 	    <form action="" name="diff" onsubmit="return ValidateDiffNum();">
   1337   6922  mjnelson 		<input name="display" value="BOF" size="8" type="text"></input>
   1338   6922  mjnelson 		<input name="real" value="0" size="8" type="hidden"></input>
   1339      0    stevel 	    </form>
   1340      0    stevel 	  </th>
   1341   3252        dp 	</tr>
   1342      0    stevel     </table>
   1343      0    stevel   </body>
   1344      0    stevel </html>
   1345      0    stevel EOF
   1346      0    stevel }
   1347      0    stevel 
   1348      0    stevel 
   1349   3252        dp 
   1350   3252        dp #
   1351   3252        dp # diff_to_html <filename> <filepath> { U | C } <comment>
   1352   3252        dp #
   1353   3252        dp # Processes the output of diff to produce an HTML file representing either
   1354   3252        dp # context or unified diffs.
   1355   3252        dp #
   1356      0    stevel diff_to_html()
   1357      0    stevel {
   1358   3252        dp 	TNAME=$1
   1359   3252        dp 	TPATH=$2
   1360   3252        dp 	DIFFTYPE=$3
   1361   3252        dp 	COMMENT=$4
   1362      0    stevel 
   1363   3252        dp 	print "$HTML<head>$STDHEAD"
   1364   3252        dp 	print "<title>$WNAME ${DIFFTYPE}diff $TPATH</title>"
   1365   3252        dp 
   1366   3252        dp 	if [[ $DIFFTYPE == "U" ]]; then
   1367   3252        dp 		print "$UDIFFCSS"
   1368   3252        dp 	fi
   1369   3252        dp 
   1370   3252        dp 	cat <<-EOF
   1371   3252        dp 	</head>
   1372   3252        dp 	<body id="SUNWwebrev">
   1373   3252        dp         <a class="print" href="javascript:print()">Print this page</a>
   1374   3252        dp 	<pre>$COMMENT</pre>
   1375   3252        dp         <pre>
   1376   3252        dp 	EOF
   1377   3252        dp 
   1378   7078  mjnelson 	html_quote | $AWK '
   1379   3252        dp 	/^--- new/	{ next }
   1380   3252        dp 	/^\+\+\+ new/	{ next }
   1381   3252        dp 	/^--- old/	{ next }
   1382   3252        dp 	/^\*\*\* old/	{ next }
   1383   3252        dp 	/^\*\*\*\*/	{ next }
   1384   3252        dp 	/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
   1385   6922  mjnelson 	/^\@\@.*\@\@$/	{ printf "</pre><hr></hr><pre>\n";
   1386   3252        dp 			  printf "<span class=\"newmarker\">%s</span>\n", $0;
   1387   3252        dp 			  next}
   1388   3252        dp 
   1389   6922  mjnelson 	/^\*\*\*/	{ printf "<hr></hr><span class=\"oldmarker\">%s</span>\n", $0;
   1390   3252        dp 			  next}
   1391   3252        dp 	/^---/		{ printf "<span class=\"newmarker\">%s</span>\n", $0;
   1392   3252        dp 			  next}
   1393   3252        dp 	/^\+/		{printf "<span class=\"new\">%s</span>\n", $0; next}
   1394   3252        dp 	/^!/		{printf "<span class=\"changed\">%s</span>\n", $0; next}
   1395   3252        dp 	/^-/		{printf "<span class=\"removed\">%s</span>\n", $0; next}
   1396   3252        dp 			{printf "%s\n", $0; next}
   1397   3252        dp 	'
   1398   3252        dp 
   1399   3252        dp 	print "</pre></body></html>\n"
   1400      0    stevel }
   1401      0    stevel 
   1402      0    stevel 
   1403   3252        dp #
   1404   3252        dp # source_to_html { new | old } <filename>
   1405   3252        dp #
   1406   3252        dp # Process a plain vanilla source file to transform it into an HTML file.
   1407   3252        dp #
   1408      0    stevel source_to_html()
   1409      0    stevel {
   1410   3252        dp 	WHICH=$1
   1411   3252        dp 	TNAME=$2
   1412      0    stevel 
   1413   3252        dp 	print "$HTML<head>$STDHEAD"
   1414   7078  mjnelson 	print "<title>$WNAME $WHICH $TNAME</title>"
   1415   3252        dp 	print "<body id=\"SUNWwebrev\">"
   1416   3252        dp 	print "<pre>"
   1417   7078  mjnelson 	html_quote | $AWK '{line += 1 ; printf "%4d %s\n", line, $0 }'
   1418   3252        dp 	print "</pre></body></html>"
   1419      0    stevel }
   1420      0    stevel 
   1421   3252        dp #
   1422   7078  mjnelson # comments_from_teamware {text|html} parent-file child-file
   1423   3252        dp #
   1424   3252        dp # Find the first delta in the child that's not in the parent.  Get the
   1425   3252        dp # newest delta from the parent, get all deltas from the child starting
   1426   3252        dp # with that delta, and then get all info starting with the second oldest
   1427   3252        dp # delta in that list (the first delta unique to the child).
   1428      0    stevel #
   1429      0    stevel # This code adapted from Bill Shannon's "spc" script
   1430   3252        dp #
   1431   3252        dp comments_from_teamware()
   1432   3252        dp {
   1433   3252        dp 	fmt=$1
   1434   3252        dp 	pfile=$PWS/$2
   1435   3252        dp 	cfile=$CWS/$3
   1436      0    stevel 
   1437   7078  mjnelson 	if [[ ! -f $PWS/${2%/*}/SCCS/s.${2##*/} && -n $RWS ]]; then
   1438   7078  mjnelson 		pfile=$RWS/$2
   1439   7078  mjnelson 	fi
   1440   7078  mjnelson 
   1441   3252        dp 	if [[ -f $pfile ]]; then
   1442   7078  mjnelson 		psid=$($SCCS prs -d:I: $pfile 2>/dev/null)
   1443   3252        dp 	else
   1444   3252        dp 		psid=1.1
   1445   3252        dp 	fi
   1446      0    stevel 
   1447   7078  mjnelson 	set -A sids $($SCCS prs -l -r$psid -d:I: $cfile 2>/dev/null)
   1448   3252        dp 	N=${#sids[@]}
   1449      0    stevel 
   1450   3252        dp 	nawkprg='
   1451   3252        dp 		/^COMMENTS:/	{p=1; continue}
   1452   3252        dp 		/^D [0-9]+\.[0-9]+/ {printf "--- %s ---\n", $2; p=0; }
   1453   3252        dp 		NF == 0u	{ continue }
   1454   3252        dp 		{if (p==0) continue; print $0 }'
   1455      0    stevel 
   1456   3252        dp 	if [[ $N -ge 2 ]]; then
   1457   3252        dp 		sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
   1458      0    stevel 
   1459   3252        dp 		if [[ $fmt == "text" ]]; then
   1460   7078  mjnelson 			$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
   1461   7078  mjnelson 			    $AWK "$nawkprg"
   1462   3252        dp 			return
   1463   3252        dp 		fi
   1464   3252        dp 
   1465   7078  mjnelson 		$SCCS prs -l -r$sid1 $cfile  2>/dev/null | \
   1466   9193      Mark 		    html_quote | its2url | $AWK "$nawkprg"
   1467   3252        dp 	fi
   1468      0    stevel }
   1469      0    stevel 
   1470   3252        dp #
   1471   7078  mjnelson # comments_from_wx {text|html} filepath
   1472   3252        dp #
   1473   7078  mjnelson # Given the pathname of a file, find its location in a "wx" active
   1474   7078  mjnelson # file list and print the following comment.  Output is either text or
   1475   7078  mjnelson # HTML; if the latter, embedded bugids (sequence of 5 or more digits)
   1476   7078  mjnelson # are turned into URLs.
   1477   7078  mjnelson #
   1478   7078  mjnelson # This is also used with Mercurial and the file list provided by hg-active.
   1479   3252        dp #
   1480   3252        dp comments_from_wx()
   1481   3252        dp {
   1482   3252        dp 	typeset fmt=$1
   1483   3252        dp 	typeset p=$2
   1484      0    stevel 
   1485   7078  mjnelson 	comm=`$AWK '
   1486   3252        dp 	$1 == "'$p'" {
   1487      0    stevel 		do getline ; while (NF > 0)
   1488      0    stevel 		getline
   1489      0    stevel 		while (NF > 0) { print ; getline }
   1490      0    stevel 		exit
   1491   3252        dp 	}' < $wxfile`
   1492   3252        dp 
   1493   7078  mjnelson 	if [[ -z $comm ]]; then
   1494   7078  mjnelson 		comm="*** NO COMMENTS ***"
   1495   7078  mjnelson 	fi
   1496   7078  mjnelson 
   1497   3252        dp 	if [[ $fmt == "text" ]]; then
   1498   7078  mjnelson 		print -- "$comm"
   1499   3252        dp 		return
   1500   3252        dp 	fi
   1501   3252        dp 
   1502   9193      Mark 	print -- "$comm" | html_quote | its2url
   1503   7078  mjnelson 
   1504      0    stevel }
   1505      0    stevel 
   1506   3252        dp #
   1507   3252        dp # getcomments {text|html} filepath parentpath
   1508   3252        dp #
   1509   3252        dp # Fetch the comments depending on what SCM mode we're in.
   1510   3252        dp #
   1511   3252        dp getcomments()
   1512   3252        dp {
   1513   3252        dp 	typeset fmt=$1
   1514   3252        dp 	typeset p=$2
   1515   3252        dp 	typeset pp=$3
   1516      0    stevel 
   1517   7310    Darren 	if [[ -n $Nflag ]]; then
   1518   7310    Darren 		return
   1519   7310    Darren 	fi
   1520   7078  mjnelson 	#
   1521   7078  mjnelson 	# Mercurial support uses a file list in wx format, so this
   1522   7078  mjnelson 	# will be used there, too
   1523   7078  mjnelson 	#
   1524   3252        dp 	if [[ -n $wxfile ]]; then
   1525   3252        dp 		comments_from_wx $fmt $p
   1526   3252        dp 	else
   1527   3252        dp 		if [[ $SCM_MODE == "teamware" ]]; then
   1528   3252        dp 			comments_from_teamware $fmt $pp $p
   1529   3252        dp 		fi
   1530   3252        dp 	fi
   1531   3252        dp }
   1532   3252        dp 
   1533   3252        dp #
   1534   3252        dp # printCI <total-changed> <inserted> <deleted> <modified> <unchanged>
   1535   3252        dp #
   1536   3252        dp # Print out Code Inspection figures similar to sccs-prt(1) format.
   1537   3252        dp #
   1538   3252        dp function printCI
   1539   3252        dp {
   1540   3252        dp 	integer tot=$1 ins=$2 del=$3 mod=$4 unc=$5
   1541   3252        dp 	typeset str
   1542   3252        dp 	if (( tot == 1 )); then
   1543   3252        dp 		str="line"
   1544   3252        dp 	else
   1545   3252        dp 		str="lines"
   1546   3252        dp 	fi
   1547   3252        dp 	printf '%d %s changed: %d ins; %d del; %d mod; %d unchg\n' \
   1548   3252        dp 	    $tot $str $ins $del $mod $unc
   1549   3252        dp }
   1550   3252        dp 
   1551   3252        dp 
   1552   3252        dp #
   1553   3252        dp # difflines <oldfile> <newfile>
   1554   3252        dp #
   1555   3252        dp # Calculate and emit number of added, removed, modified and unchanged lines,
   1556   3252        dp # and total lines changed, the sum of added + removed + modified.
   1557   3252        dp #
   1558      0    stevel function difflines
   1559      0    stevel {
   1560   3252        dp 	integer tot mod del ins unc err
   1561   3252        dp 	typeset filename
   1562      0    stevel 
   1563   7078  mjnelson 	eval $( diff -e $1 $2 | $AWK '
   1564   3252        dp 	# Change range of lines: N,Nc
   1565   3252        dp 	/^[0-9]*,[0-9]*c$/ {
   1566   3252        dp 		n=split(substr($1,1,length($1)-1), counts, ",");
   1567   3252        dp 		if (n != 2) {
   1568   3252        dp 		    error=2
   1569   3252        dp 		    exit;
   1570   3252        dp 		}
   1571   3252        dp 		#
   1572   3252        dp 		# 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
   1573   3252        dp 		# following would be 5 - 3 = 2! Hence +1 for correction.
   1574   3252        dp 		#
   1575   3252        dp 		r=(counts[2]-counts[1])+1;
   1576   3252        dp 
   1577   3252        dp 		#
   1578   3252        dp 		# Now count replacement lines: each represents a change instead
   1579   3252        dp 		# of a delete, so increment c and decrement r.
   1580   3252        dp 		#
   1581   3252        dp 		while (getline != /^\.$/) {
   1582   3252        dp 			c++;
   1583   3252        dp 			r--;
   1584   3252        dp 		}
   1585   3252        dp 		#
   1586   3252        dp 		# If there were more replacement lines than original lines,
   1587   3252        dp 		# then r will be negative; in this case there are no deletions,
   1588   3252        dp 		# but there are r changes that should be counted as adds, and
   1589   3252        dp 		# since r is negative, subtract it from a and add it to c.
   1590   3252        dp 		#
   1591   3252        dp 		if (r < 0) {
   1592   3252        dp 			a-=r;
   1593   3252        dp 			c+=r;
   1594   3252        dp 		}
   1595   3252        dp 
   1596   3252        dp 		#
   1597   3252        dp 		# If there were more original lines than replacement lines, then
   1598   3252        dp 		# r will be positive; in this case, increment d by that much.
   1599   3252        dp 		#
   1600   3252        dp 		if (r > 0) {
   1601   3252        dp 			d+=r;
   1602   3252        dp 		}
   1603   3252        dp 		next;
   1604      0    stevel 	}
   1605   3252        dp 
   1606   3252        dp 	# Change lines: Nc
   1607   3252        dp 	/^[0-9].*c$/ {
   1608   3252        dp 		# The first line is a replacement; any more are additions.
   1609   3252        dp 		if (getline != /^\.$/) {
   1610   3252        dp 			c++;
   1611   3252        dp 			while (getline != /^\.$/) a++;
   1612   3252        dp 		}
   1613   3252        dp 		next;
   1614      0    stevel 	}
   1615   3252        dp 
   1616   3252        dp 	# Add lines: both Na and N,Na
   1617   3252        dp 	/^[0-9].*a$/ {
   1618   3252        dp 		while (getline != /^\.$/) a++;
   1619   3252        dp 		next;
   1620      0    stevel 	}
   1621   3252        dp 
   1622   3252        dp 	# Delete range of lines: N,Nd
   1623   3252        dp 	/^[0-9]*,[0-9]*d$/ {
   1624   3252        dp 		n=split(substr($1,1,length($1)-1), counts, ",");
   1625   3252        dp 		if (n != 2) {
   1626   3252        dp 			error=2
   1627   3252        dp 			exit;
   1628   3252        dp 		}
   1629   3252        dp 		#
   1630   3252        dp 		# 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
   1631   3252        dp 		# following would be 5 - 3 = 2! Hence +1 for correction.
   1632   3252        dp 		#
   1633   3252        dp 		r=(counts[2]-counts[1])+1;
   1634      0    stevel 		d+=r;
   1635   3252        dp 		next;
   1636      0    stevel 	}
   1637      0    stevel 
   1638   3252        dp 	# Delete line: Nd.   For example 10d says line 10 is deleted.
   1639   3252        dp 	/^[0-9]*d$/ {d++; next}
   1640   3252        dp 
   1641   3252        dp 	# Should not get here!
   1642   3252        dp 	{
   1643   3252        dp 		error=1;
   1644   3252        dp 		exit;
   1645      0    stevel 	}
   1646      0    stevel 
   1647   3252        dp 	# Finish off - print results
   1648   3252        dp 	END {
   1649   3252        dp 		printf("tot=%d;mod=%d;del=%d;ins=%d;err=%d\n",
   1650   3252        dp 		    (c+d+a), c, d, a, error);
   1651   3252        dp 	}' )
   1652      0    stevel 
   1653   7078  mjnelson 	# End of $AWK, Check to see if any trouble occurred.
   1654   3252        dp 	if (( $? > 0 || err > 0 )); then
   1655   3252        dp 		print "Unexpected Error occurred reading" \
   1656   3252        dp 		    "\`diff -e $1 $2\`: \$?=$?, err=" $err
   1657   3252        dp 		return
   1658   3252        dp 	fi
   1659      0    stevel 
   1660      0    stevel 	# Accumulate totals
   1661      0    stevel 	(( TOTL += tot ))
   1662   3252        dp 	(( TMOD += mod ))
   1663   3252        dp 	(( TDEL += del ))
   1664      0    stevel 	(( TINS += ins ))
   1665      0    stevel 	# Calculate unchanged lines
   1666   7078  mjnelson 	unc=`wc -l < $1`
   1667      0    stevel 	if (( unc > 0 )); then
   1668   3252        dp 		(( unc -= del + mod ))
   1669   3252        dp 		(( TUNC += unc ))
   1670      0    stevel 	fi
   1671      0    stevel 	# print summary
   1672   3252        dp 	print "<span class=\"lineschanged\">"
   1673   3252        dp 	printCI $tot $ins $del $mod $unc
   1674   3252        dp 	print "</span>"
   1675      0    stevel }
   1676      0    stevel 
   1677   3252        dp 
   1678      0    stevel #
   1679   3252        dp # flist_from_wx
   1680   3252        dp #
   1681   3252        dp # Sets up webrev to source its information from a wx-formatted file.
   1682   3252        dp # Sets the global 'wxfile' variable.
   1683   3252        dp #
   1684   3252        dp function flist_from_wx
   1685      0    stevel {
   1686   3252        dp 	typeset argfile=$1
   1687   3252        dp 	if [[ -n ${argfile%%/*} ]]; then
   1688   3252        dp 		#
   1689   3252        dp 		# If the wx file pathname is relative then make it absolute
   1690   3252        dp 		# because the webrev does a "cd" later on.
   1691   3252        dp 		#
   1692   3252        dp 		wxfile=$PWD/$argfile
   1693   3252        dp 	else
   1694   3252        dp 		wxfile=$argfile
   1695   3252        dp 	fi
   1696   3252        dp 
   1697   7078  mjnelson 	$AWK '{ c = 1; print;
   1698   3252        dp 	  while (getline) {
   1699   3252        dp 		if (NF == 0) { c = -c; continue }
   1700   3252        dp 		if (c > 0) print
   1701   3252        dp 	  }
   1702   3252        dp 	}' $wxfile > $FLIST
   1703   3252        dp 
   1704   3252        dp 	print " Done."
   1705      0    stevel }
   1706      0    stevel 
   1707      0    stevel #
   1708   3252        dp # flist_from_teamware [ <args-to-putback-n> ]
   1709      0    stevel #
   1710   3252        dp # Generate the file list by extracting file names from a putback -n.  Some
   1711   3252        dp # names may come from the "update/create" messages and others from the
   1712   3252        dp # "currently checked out" warning.  Renames are detected here too.  Extract
   1713   3252        dp # values for CODEMGR_WS and CODEMGR_PARENT from the output of the putback
   1714   3252        dp # -n as well, but remove them if they are already defined.
   1715   3252        dp #
   1716   3252        dp function flist_from_teamware
   1717   3252        dp {
   1718   7078  mjnelson 	if [[ -n $codemgr_parent && -z $parent_webrev ]]; then
   1719   3252        dp 		if [[ ! -d $codemgr_parent/Codemgr_wsdata ]]; then
   1720   3252        dp 			print -u2 "parent $codemgr_parent doesn't look like a" \
   1721   3252        dp 			    "valid teamware workspace"
   1722   3252        dp 			exit 1
   1723   3252        dp 		fi
   1724   3252        dp 		parent_args="-p $codemgr_parent"
   1725   3252        dp 	fi
   1726   3252        dp 
   1727   3252        dp 	print " File list from: 'putback -n $parent_args $*' ... \c"
   1728   3252        dp 
   1729   3252        dp 	putback -n $parent_args $* 2>&1 |
   1730   7078  mjnelson 	    $AWK '
   1731   3252        dp 		/^update:|^create:/	{print $2}
   1732   3252        dp 		/^Parent workspace:/	{printf("CODEMGR_PARENT=%s\n",$3)}
   1733   3252        dp 		/^Child workspace:/	{printf("CODEMGR_WS=%s\n",$3)}
   1734   3252        dp 		/^The following files are currently checked out/ {p = 1; continue}
   1735   3252        dp 		NF == 0			{p=0 ; continue}
   1736   3252        dp 		/^rename/		{old=$3}
   1737   3252        dp 		$1 == "to:"		{print $2, old}
   1738   3252        dp 		/^"/			{continue}
   1739   3252        dp 		p == 1			{print $1}' |
   1740   3252        dp 	    sort -r -k 1,1 -u | sort > $FLIST
   1741   3252        dp 
   1742   3252        dp 	print " Done."
   1743   3252        dp }
   1744   3252        dp 
   1745   7078  mjnelson #
   1746   7078  mjnelson # Call hg-active to get the active list output in the wx active list format
   1747   7078  mjnelson #
   1748   7078  mjnelson function hg_active_wxfile
   1749   7078  mjnelson {
   1750   7078  mjnelson 	typeset child=$1
   1751   7078  mjnelson 	typeset parent=$2
   1752   7078  mjnelson 
   1753   7078  mjnelson 	TMPFLIST=/tmp/$$.active
   1754   7298      Mark 	$HG_ACTIVE -w $child -p $parent -o $TMPFLIST
   1755   7078  mjnelson 	wxfile=$TMPFLIST
   1756   7078  mjnelson }
   1757   7078  mjnelson 
   1758   7078  mjnelson #
   1759   7078  mjnelson # flist_from_mercurial
   1760   7078  mjnelson # Call hg-active to get a wx-style active list, and hand it off to
   1761   7078  mjnelson # flist_from_wx
   1762   7078  mjnelson #
   1763  10789    Edward function flist_from_mercurial
   1764   7078  mjnelson {
   1765   7078  mjnelson 	typeset child=$1
   1766   7078  mjnelson 	typeset parent=$2
   1767   7078  mjnelson 
   1768   7078  mjnelson 	print " File list from: hg-active -p $parent ...\c"
   1769   7078  mjnelson 
   1770   7078  mjnelson 	if [[ ! -x $HG_ACTIVE ]]; then
   1771   7078  mjnelson 		print		# Blank line for the \c above
   1772   7078  mjnelson 		print -u2 "Error: hg-active tool not found.  Exiting"
   1773   7078  mjnelson 		exit 1
   1774   7078  mjnelson 	fi
   1775   7078  mjnelson 	hg_active_wxfile $child $parent
   1776  10789    Edward 
   1777   7078  mjnelson 	# flist_from_wx prints the Done, so we don't have to.
   1778   7078  mjnelson 	flist_from_wx $TMPFLIST
   1779   7078  mjnelson }
   1780   7078  mjnelson 
   1781   7078  mjnelson #
   1782   7078  mjnelson # flist_from_subversion
   1783   7078  mjnelson #
   1784   7078  mjnelson # Generate the file list by extracting file names from svn status.
   1785   7078  mjnelson #
   1786   7078  mjnelson function flist_from_subversion
   1787   7078  mjnelson {
   1788   7078  mjnelson 	CWS=$1
   1789   7078  mjnelson 	OLDPWD=$2
   1790   7078  mjnelson 
   1791   7078  mjnelson 	cd $CWS
   1792   7078  mjnelson 	print -u2 " File list from: svn status ... \c"
   1793   7078  mjnelson 	svn status | $AWK '/^[ACDMR]/ { print $NF }' > $FLIST
   1794   7078  mjnelson 	print -u2 " Done."
   1795   7078  mjnelson 	cd $OLDPWD
   1796   7078  mjnelson }
   1797   7078  mjnelson 
   1798   3252        dp function env_from_flist
   1799   3252        dp {
   1800   3252        dp 	[[ -r $FLIST ]] || return
   1801   3252        dp 
   1802   3252        dp 	#
   1803   3252        dp 	# Use "eval" to set env variables that are listed in the file
   1804   3252        dp 	# list.  Then copy those into our local versions of those
   1805   3252        dp 	# variables if they have not been set already.
   1806   3252        dp 	#
   1807   9079  Vladimir 	eval `$SED -e "s/#.*$//" $FLIST | $GREP = `
   1808   3252        dp 
   1809   7078  mjnelson 	if [[ -z $codemgr_ws && -n $CODEMGR_WS ]]; then
   1810   7078  mjnelson 		codemgr_ws=$CODEMGR_WS
   1811   7078  mjnelson 		export CODEMGR_WS
   1812   7078  mjnelson 	fi
   1813   3252        dp 
   1814   3252        dp 	#
   1815   3252        dp 	# Check to see if CODEMGR_PARENT is set in the flist file.
   1816   3252        dp 	#
   1817   7078  mjnelson 	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
   1818   7078  mjnelson 		codemgr_parent=$CODEMGR_PARENT
   1819   7078  mjnelson 		export CODEMGR_PARENT
   1820   3252        dp 	fi
   1821   3252        dp }
   1822   3252        dp 
   1823   3295        dp function look_for_prog
   1824   3295        dp {
   1825   3295        dp 	typeset path
   1826   3295        dp 	typeset ppath
   1827   3295        dp 	typeset progname=$1
   1828   3295        dp 
   1829   3295        dp 	ppath=$PATH
   1830   3295        dp 	ppath=$ppath:/usr/sfw/bin:/usr/bin:/usr/sbin
   1831   3295        dp 	ppath=$ppath:/opt/teamware/bin:/opt/onbld/bin
   1832   7078  mjnelson 	ppath=$ppath:/opt/onbld/bin/`uname -p`
   1833   3295        dp 
   1834   3295        dp 	PATH=$ppath prog=`whence $progname`
   1835   3295        dp 	if [[ -n $prog ]]; then
   1836   3295        dp 		print $prog
   1837   3295        dp 	fi
   1838   3295        dp }
   1839   7078  mjnelson 
   1840   7078  mjnelson function get_file_mode
   1841   7078  mjnelson {
   1842   7078  mjnelson 	$PERL -e '
   1843   7078  mjnelson 		if (@stat = stat($ARGV[0])) {
   1844   7078  mjnelson 			$mode = $stat[2] & 0777;
   1845   7078  mjnelson 			printf "%03o\n", $mode;
   1846   7078  mjnelson 			exit 0;
   1847   7078  mjnelson 		} else {
   1848   7078  mjnelson 			exit 1;
   1849   7078  mjnelson 		}
   1850   7078  mjnelson 	    ' $1
   1851   7078  mjnelson }
   1852   7078  mjnelson 
   1853   7078  mjnelson function build_old_new_teamware
   1854   7078  mjnelson {
   1855   7078  mjnelson 	typeset olddir="$1"
   1856   7078  mjnelson 	typeset newdir="$2"
   1857   7078  mjnelson 
   1858   7078  mjnelson 	# If the child's version doesn't exist then
   1859   7078  mjnelson 	# get a readonly copy.
   1860   7078  mjnelson 
   1861   7078  mjnelson 	if [[ ! -f $CWS/$DIR/$F && -f $CWS/$DIR/SCCS/s.$F ]]; then
   1862   7078  mjnelson 		$SCCS get -s -p $CWS/$DIR/$F > $CWS/$DIR/$F
   1863   7078  mjnelson 	fi
   1864   7078  mjnelson 
   1865   7078  mjnelson 	# The following two sections propagate file permissions the
   1866   7078  mjnelson 	# same way SCCS does.  If the file is already under version
   1867   7078  mjnelson 	# control, always use permissions from the SCCS/s.file.  If
   1868   7078  mjnelson 	# the file is not under SCCS control, use permissions from the
   1869   7078  mjnelson 	# working copy.  In all cases, the file copied to the webrev
   1870   7078  mjnelson 	# is set to read only, and group/other permissions are set to
   1871   7078  mjnelson 	# match those of the file owner.  This way, even if the file
   1872   7078  mjnelson 	# is currently checked out, the webrev will display the final
   1873   7078  mjnelson 	# permissions that would result after check in.
   1874   7078  mjnelson 
   1875   7078  mjnelson 	#
   1876   7078  mjnelson 	# Snag new version of file.
   1877   7078  mjnelson 	#
   1878   7078  mjnelson 	rm -f $newdir/$DIR/$F
   1879   7078  mjnelson 	cp $CWS/$DIR/$F $newdir/$DIR/$F
   1880   7078  mjnelson 	if [[ -f $CWS/$DIR/SCCS/s.$F ]]; then
   1881   7078  mjnelson 		chmod `get_file_mode $CWS/$DIR/SCCS/s.$F` \
   1882   7078  mjnelson 		    $newdir/$DIR/$F
   1883   7078  mjnelson 	fi
   1884   7078  mjnelson 	chmod u-w,go=u $newdir/$DIR/$F
   1885   7078  mjnelson 
   1886   7078  mjnelson 	#
   1887   7078  mjnelson 	# Get the parent's version of the file. First see whether the
   1888   7078  mjnelson 	# child's version is checked out and get the parent's version
   1889   7078  mjnelson 	# with keywords expanded or unexpanded as appropriate.
   1890   7078  mjnelson 	#
   1891   7078  mjnelson 	if [[ -f $PWS/$PDIR/$PF && ! -f $PWS/$PDIR/SCCS/s.$PF && \
   1892   7078  mjnelson 	    ! -f $PWS/$PDIR/SCCS/p.$PF ]]; then
   1893   7078  mjnelson 		# Parent is not a real workspace, but just a raw
   1894   7078  mjnelson 		# directory tree - use the file that's there as
   1895   7078  mjnelson 		# the old file.
   1896   7078  mjnelson 
   1897   7078  mjnelson 		rm -f $olddir/$PDIR/$PF
   1898   7078  mjnelson 		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
   1899   7078  mjnelson 	else
   1900   7078  mjnelson 		if [[ -f $PWS/$PDIR/SCCS/s.$PF ]]; then
   1901   7078  mjnelson 			real_parent=$PWS
   1902   7078  mjnelson 		else
   1903   7078  mjnelson 			real_parent=$RWS
   1904   7078  mjnelson 		fi
   1905   7078  mjnelson 
   1906   7078  mjnelson 		rm -f $olddir/$PDIR/$PF
   1907   7078  mjnelson 
   1908   7078  mjnelson 		if [[ -f $real_parent/$PDIR/$PF ]]; then
   1909   7078  mjnelson 			if [ -f $CWS/$DIR/SCCS/p.$F ]; then
   1910   7078  mjnelson 				$SCCS get -s -p -k $real_parent/$PDIR/$PF > \
   1911   7078  mjnelson 				    $olddir/$PDIR/$PF
   1912   7078  mjnelson 			else
   1913   7078  mjnelson 				$SCCS get -s -p    $real_parent/$PDIR/$PF > \
   1914   7078  mjnelson 				    $olddir/$PDIR/$PF
   1915   7078  mjnelson 			fi
   1916   7078  mjnelson 			chmod `get_file_mode $real_parent/$PDIR/SCCS/s.$PF` \
   1917   7078  mjnelson 			    $olddir/$PDIR/$PF
   1918   7078  mjnelson 		fi
   1919   7078  mjnelson 	fi
   1920   7078  mjnelson 	if [[ -f $olddir/$PDIR/$PF ]]; then
   1921   7078  mjnelson 		chmod u-w,go=u $olddir/$PDIR/$PF
   1922   7078  mjnelson 	fi
   1923   7078  mjnelson }
   1924   7078  mjnelson 
   1925   7078  mjnelson function build_old_new_mercurial
   1926   7078  mjnelson {
   1927   7078  mjnelson 	typeset olddir="$1"
   1928   7078  mjnelson 	typeset newdir="$2"
   1929   7078  mjnelson 	typeset old_mode=
   1930   7078  mjnelson 	typeset new_mode=
   1931   7078  mjnelson 	typeset file
   1932   7078  mjnelson 
   1933   7078  mjnelson 	#
   1934   7078  mjnelson 	# Get old file mode, from the parent revision manifest entry.
   1935   7078  mjnelson 	# Mercurial only stores a "file is executable" flag, but the
   1936   7078  mjnelson 	# manifest will display an octal mode "644" or "755".
   1937   7078  mjnelson 	#
   1938   7078  mjnelson 	if [[ "$PDIR" == "." ]]; then
   1939   7078  mjnelson 		file="$PF"
   1940   7078  mjnelson 	else
   1941   7078  mjnelson 		file="$PDIR/$PF"
   1942   7078  mjnelson 	fi
   1943   9079  Vladimir 	file=`echo $file | $SED 's#/#\\\/#g'`
   1944   7078  mjnelson 	# match the exact filename, and return only the permission digits
   1945   9079  Vladimir 	old_mode=`$SED -n -e "/^\\(...\\) . ${file}$/s//\\1/p" \
   1946   7078  mjnelson 	    < $HG_PARENT_MANIFEST`
   1947   7078  mjnelson 
   1948   7078  mjnelson 	#
   1949   7078  mjnelson 	# Get new file mode, directly from the filesystem.
   1950   7078  mjnelson 	# Normalize the mode to match Mercurial's behavior.
   1951   7078  mjnelson 	#
   1952   7078  mjnelson 	new_mode=`get_file_mode $CWS/$DIR/$F`
   1953   7078  mjnelson 	if [[ -n "$new_mode" ]]; then
   1954   7078  mjnelson 		if [[ "$new_mode" = *[1357]* ]]; then
   1955   7078  mjnelson 			new_mode=755
   1956   7078  mjnelson 		else
   1957   7078  mjnelson 			new_mode=644
   1958   7078  mjnelson 		fi
   1959   7078  mjnelson 	fi
   1960   7078  mjnelson 
   1961   7078  mjnelson 	#
   1962   7078  mjnelson 	# new version of the file.
   1963   7078  mjnelson 	#
   1964   7078  mjnelson 	rm -rf $newdir/$DIR/$F
   1965   7078  mjnelson 	if [[ -e $CWS/$DIR/$F ]]; then
   1966   7078  mjnelson 		cp $CWS/$DIR/$F $newdir/$DIR/$F
   1967   7078  mjnelson 		if [[ -n $new_mode ]]; then
   1968   7078  mjnelson 			chmod $new_mode $newdir/$DIR/$F
   1969   7078  mjnelson 		else
   1970   7078  mjnelson 			# should never happen
   1971   7078  mjnelson 			print -u2 "ERROR: set mode of $newdir/$DIR/$F"
   1972   7078  mjnelson 		fi
   1973   7078  mjnelson 	fi
   1974   7078  mjnelson 
   1975   7078  mjnelson 	#
   1976   7078  mjnelson 	# parent's version of the file
   1977   7078  mjnelson 	#
   1978   7078  mjnelson 	# Note that we get this from the last version common to both
   1979   7078  mjnelson 	# ourselves and the parent.  References are via $CWS since we have no
   1980   7078  mjnelson 	# guarantee that the parent workspace is reachable via the filesystem.
   1981   7078  mjnelson 	#
   1982   7078  mjnelson 	if [[ -n $parent_webrev && -e $PWS/$PDIR/$PF ]]; then
   1983   7078  mjnelson 		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
   1984   7078  mjnelson 	elif [[ -n $HG_PARENT ]]; then
   1985   7078  mjnelson 		hg cat -R $CWS -r $HG_PARENT $CWS/$PDIR/$PF > \
   1986   7078  mjnelson 		    $olddir/$PDIR/$PF 2>/dev/null
   1987   7078  mjnelson 
   1988   8018  Vladimir 		if (( $? != 0 )); then
   1989   7078  mjnelson 			rm -f $olddir/$PDIR/$PF
   1990   7078  mjnelson 		else
   1991   7078  mjnelson 			if [[ -n $old_mode ]]; then
   1992   7078  mjnelson 				chmod $old_mode $olddir/$PDIR/$PF
   1993   7078  mjnelson 			else
   1994   7078  mjnelson 				# should never happen
   1995   7078  mjnelson 				print -u2 "ERROR: set mode of $olddir/$PDIR/$PF"
   1996   7078  mjnelson 			fi
   1997   7078  mjnelson 		fi
   1998   7078  mjnelson 	fi
   1999   7078  mjnelson }
   2000   7078  mjnelson 
   2001   7078  mjnelson function build_old_new_subversion
   2002   7078  mjnelson {
   2003   7078  mjnelson 	typeset olddir="$1"
   2004   7078  mjnelson 	typeset newdir="$2"
   2005   7078  mjnelson 
   2006   7078  mjnelson 	# Snag new version of file.
   2007   7078  mjnelson 	rm -f $newdir/$DIR/$F
   2008   7078  mjnelson 	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
   2009   7078  mjnelson 
   2010   7078  mjnelson 	if [[ -n $PWS && -e $PWS/$PDIR/$PF ]]; then
   2011   7078  mjnelson 		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
   2012   7078  mjnelson 	else
   2013   7078  mjnelson 		# Get the parent's version of the file.
   2014   7078  mjnelson 		svn status $CWS/$DIR/$F | read stat file
   2015   7078  mjnelson 		if [[ $stat != "A" ]]; then
   2016   7078  mjnelson 			svn cat -r BASE $CWS/$DIR/$F > $olddir/$PDIR/$PF
   2017   7078  mjnelson 		fi
   2018   7078  mjnelson 	fi
   2019   7078  mjnelson }
   2020   7078  mjnelson 
   2021   7078  mjnelson function build_old_new_unknown
   2022   7078  mjnelson {
   2023   7078  mjnelson 	typeset olddir="$1"
   2024   7078  mjnelson 	typeset newdir="$2"
   2025   7078  mjnelson 
   2026   7078  mjnelson 	#
   2027   7078  mjnelson 	# Snag new version of file.
   2028   7078  mjnelson 	#
   2029   7078  mjnelson 	rm -f $newdir/$DIR/$F
   2030   7078  mjnelson 	[[ -e $CWS/$DIR/$F ]] && cp $CWS/$DIR/$F $newdir/$DIR/$F
   2031   7078  mjnelson 
   2032   7078  mjnelson 	#
   2033   7078  mjnelson 	# Snag the parent's version of the file.
   2034  10789    Edward 	#
   2035   7078  mjnelson 	if [[ -f $PWS/$PDIR/$PF ]]; then
   2036   7078  mjnelson 		rm -f $olddir/$PDIR/$PF
   2037   7078  mjnelson 		cp $PWS/$PDIR/$PF $olddir/$PDIR/$PF
   2038   7078  mjnelson 	fi
   2039   7078  mjnelson }
   2040   7078  mjnelson 
   2041   7078  mjnelson function build_old_new
   2042   7078  mjnelson {
   2043   7078  mjnelson 	typeset WDIR=$1
   2044   7078  mjnelson 	typeset PWS=$2
   2045   7078  mjnelson 	typeset PDIR=$3
   2046   7078  mjnelson 	typeset PF=$4
   2047   7078  mjnelson 	typeset CWS=$5
   2048   7078  mjnelson 	typeset DIR=$6
   2049   7078  mjnelson 	typeset F=$7
   2050   7078  mjnelson 
   2051   7078  mjnelson 	typeset olddir="$WDIR/raw_files/old"
   2052   7078  mjnelson 	typeset newdir="$WDIR/raw_files/new"
   2053   7078  mjnelson 
   2054   7078  mjnelson 	mkdir -p $olddir/$PDIR
   2055   7078  mjnelson 	mkdir -p $newdir/$DIR
   2056   7078  mjnelson 
   2057   7078  mjnelson 	if [[ $SCM_MODE == "teamware" ]]; then
   2058   7078  mjnelson 		build_old_new_teamware "$olddir" "$newdir"
   2059   7078  mjnelson 	elif [[ $SCM_MODE == "mercurial" ]]; then
   2060   7078  mjnelson 		build_old_new_mercurial "$olddir" "$newdir"
   2061   7078  mjnelson 	elif [[ $SCM_MODE == "subversion" ]]; then
   2062   7078  mjnelson 		build_old_new_subversion "$olddir" "$newdir"
   2063   7078  mjnelson 	elif [[ $SCM_MODE == "unknown" ]]; then
   2064   7078  mjnelson 		build_old_new_unknown "$olddir" "$newdir"
   2065   7078  mjnelson 	fi
   2066   7078  mjnelson 
   2067   7078  mjnelson 	if [[ ! -f $olddir/$PDIR/$PF && ! -f $newdir/$DIR/$F ]]; then
   2068   7078  mjnelson 		print "*** Error: file not in parent or child"
   2069   7078  mjnelson 		return 1
   2070   7078  mjnelson 	fi
   2071   7078  mjnelson 	return 0
   2072   7078  mjnelson }
   2073   7078  mjnelson 
   2074   3295        dp 
   2075   3252        dp #
   2076   3252        dp # Usage message.
   2077   3252        dp #
   2078   3252        dp function usage
   2079   3252        dp {
   2080   3252        dp 	print 'Usage:\twebrev [common-options]
   2081   3252        dp 	webrev [common-options] ( <file> | - )
   2082   3252        dp 	webrev [common-options] -w <wx file>
   2083   3252        dp 
   2084   3252        dp Options:
   2085   9193      Mark 	-C <filename>: Use <filename> for the information tracking configuration.
   2086   8365  Vladimir 	-D: delete remote webrev
   2087   8365  Vladimir 	-i <filename>: Include <filename> in the index.html file.
   2088   9193      Mark 	-I <filename>: Use <filename> for the information tracking registry.
   2089   8365  Vladimir 	-n: do not generate the webrev (useful with -U)
   2090   3252        dp 	-O: Print bugids/arc cases suitable for OpenSolaris.
   2091   3252        dp 	-o <outdir>: Output webrev to specified directory.
   2092   3252        dp 	-p <compare-against>: Use specified parent wkspc or basis for comparison
   2093   8018  Vladimir 	-t <remote_target>: Specify remote destination for webrev upload
   2094   8018  Vladimir 	-U: upload the webrev to remote destination
   2095   3252        dp 	-w <wxfile>: Use specified wx active file.
   2096   3252        dp 
   2097   3252        dp Environment:
   2098   3252        dp 	WDIR: Control the output directory.
   2099   8365  Vladimir 	WEBREV_TRASH_DIR: Set directory for webrev delete.
   2100   3252        dp 
   2101   7078  mjnelson SCM Specific Options:
   2102   7078  mjnelson 	TeamWare: webrev [common-options] -l [arguments to 'putback']
   2103   7078  mjnelson 
   2104   3252        dp SCM Environment:
   2105   7078  mjnelson 	CODEMGR_WS: Workspace location.
   2106   7078  mjnelson 	CODEMGR_PARENT: Parent workspace location.
   2107   3252        dp '
   2108   3252        dp 
   2109   3252        dp 	exit 2
   2110   3252        dp }
   2111   3252        dp 
   2112   3252        dp #
   2113   3252        dp #
   2114   3252        dp # Main program starts here
   2115   3252        dp #
   2116   3252        dp #
   2117      0    stevel 
   2118      0    stevel trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
   2119      0    stevel 
   2120      0    stevel set +o noclobber
   2121      0    stevel 
   2122   7078  mjnelson PATH=$(dirname $(whence $0)):$PATH
   2123   7078  mjnelson 
   2124   3295        dp [[ -z $WDIFF ]] && WDIFF=`look_for_prog wdiff`
   2125   3295        dp [[ -z $WX ]] && WX=`look_for_prog wx`
   2126   7078  mjnelson [[ -z $HG_ACTIVE ]] && HG_ACTIVE=`look_for_prog hg-active`
   2127   7078  mjnelson [[ -z $WHICH_SCM ]] && WHICH_SCM=`look_for_prog which_scm`
   2128   3295        dp [[ -z $CODEREVIEW ]] && CODEREVIEW=`look_for_prog codereview`
   2129   3295        dp [[ -z $PS2PDF ]] && PS2PDF=`look_for_prog ps2pdf`
   2130   3295        dp [[ -z $PERL ]] && PERL=`look_for_prog perl`
   2131   8018  Vladimir [[ -z $RSYNC ]] && RSYNC=`look_for_prog rsync`
   2132   7078  mjnelson [[ -z $SCCS ]] && SCCS=`look_for_prog sccs`
   2133   7078  mjnelson [[ -z $AWK ]] && AWK=`look_for_prog nawk`
   2134   7078  mjnelson [[ -z $AWK ]] && AWK=`look_for_prog gawk`
   2135   7078  mjnelson [[ -z $AWK ]] && AWK=`look_for_prog awk`
   2136   8018  Vladimir [[ -z $SCP ]] && SCP=`look_for_prog scp`
   2137   9079  Vladimir [[ -z $SED ]] && SED=`look_for_prog sed`
   2138   8018  Vladimir [[ -z $SFTP ]] && SFTP=`look_for_prog sftp`
   2139  10789    Edward [[ -z $SORT ]] && SORT=`look_for_prog sort`
   2140   8018  Vladimir [[ -z $MKTEMP ]] && MKTEMP=`look_for_prog mktemp`
   2141   8018  Vladimir [[ -z $GREP ]] && GREP=`look_for_prog grep`
   2142   8365  Vladimir [[ -z $FIND ]] && FIND=`look_for_prog find`
   2143   7078  mjnelson 
   2144   8365  Vladimir # set name of trash directory for remote webrev deletion
   2145   8365  Vladimir TRASH_DIR=".trash"
   2146   8365  Vladimir [[ -n $WEBREV_TRASH_DIR ]] && TRASH_DIR=$WEBREV_TRASH_DIR
   2147   3295        dp 
   2148   3295        dp if [[ ! -x $PERL ]]; then
   2149   3295        dp 	print -u2 "Error: No perl interpreter found.  Exiting."
   2150   7078  mjnelson 	exit 1
   2151   7078  mjnelson fi
   2152   7078  mjnelson 
   2153   7078  mjnelson if [[ ! -x $WHICH_SCM ]]; then
   2154   7078  mjnelson 	print -u2 "Error: Could not find which_scm.  Exiting."
   2155   3295        dp 	exit 1
   2156   3252        dp fi
   2157   3295        dp 
   2158   3295        dp #
   2159   3295        dp # These aren't fatal, but we want to note them to the user.
   2160   3295        dp # We don't warn on the absence of 'wx' until later when we've
   2161   3295        dp # determined that we actually need to try to invoke it.
   2162   3295        dp #
   2163   3295        dp [[ ! -x $CODEREVIEW ]] && print -u2 "WARNING: codereview(1) not found."
   2164   3295        dp [[ ! -x $PS2PDF ]] && print -u2 "WARNING: ps2pdf(1) not found."
   2165   3295        dp [[ ! -x $WDIFF ]] && print -u2 "WARNING: wdiff not found."
   2166      0    stevel 
   2167      0    stevel # Declare global total counters.
   2168   3252        dp integer TOTL TINS TDEL TMOD TUNC
   2169      0    stevel 
   2170   8365  Vladimir # default remote host for upload/delete
   2171   8365  Vladimir typeset -r DEFAULT_REMOTE_HOST="cr.opensolaris.org"
   2172   9079  Vladimir # prefixes for upload targets
   2173   9079  Vladimir typeset -r rsync_prefix="rsync://"
   2174   9079  Vladimir typeset -r ssh_prefix="ssh://"
   2175   8365  Vladimir 
   2176   9193      Mark Cflag=
   2177   8365  Vladimir Dflag=
   2178   3295        dp flist_mode=
   2179   3295        dp flist_file=
   2180   3252        dp iflag=
   2181   9193      Mark Iflag=
   2182   8018  Vladimir lflag=
   2183   8018  Vladimir Nflag=
   2184   8018  Vladimir nflag=
   2185   8018  Vladimir Oflag=
   2186   3252        dp oflag=
   2187   3252        dp pflag=
   2188   8018  Vladimir tflag=
   2189   8018  Vladimir uflag=
   2190   8018  Vladimir Uflag=
   2191   3252        dp wflag=
   2192   8018  Vladimir remote_target=
   2193   8365  Vladimir 
   2194   8365  Vladimir #
   2195   8365  Vladimir # NOTE: when adding/removing options it is necessary to sync the list
   2196  10789    Edward #	with usr/src/tools/onbld/hgext/cdm.py
   2197   8365  Vladimir #
   2198   9561  Vladimir while getopts "C:Di:I:lnNo:Op:t:Uw" opt
   2199   3252        dp do
   2200   3252        dp 	case $opt in
   2201   9193      Mark 	C)	Cflag=1
   2202   9193      Mark 		ITSCONF=$OPTARG;;
   2203   9193      Mark 
   2204   8365  Vladimir 	D)	Dflag=1;;
   2205   8365  Vladimir 
   2206   3252        dp 	i)	iflag=1
   2207   3252        dp 		INCLUDE_FILE=$OPTARG;;
   2208   9193      Mark 
   2209   9193      Mark 	I)	Iflag=1
   2210   9193      Mark 		ITSREG=$OPTARG;;
   2211   3252        dp 
   2212   3252        dp 	#
   2213   3252        dp 	# If -l has been specified, we need to abort further options
   2214   3252        dp 	# processing, because subsequent arguments are going to be
   2215   3252        dp 	# arguments to 'putback -n'.
   2216   3252        dp 	#
   2217   3252        dp 	l)	lflag=1
   2218   3252        dp 		break;;
   2219   3252        dp 
   2220   8018  Vladimir 	N)	Nflag=1;;
   2221   8018  Vladimir 
   2222   8018  Vladimir 	n)	nflag=1;;
   2223   3252        dp 
   2224   3252        dp 	O)	Oflag=1;;
   2225   7310    Darren 
   2226   8018  Vladimir 	o)	oflag=1
   2227   8018  Vladimir 		WDIR=$OPTARG;;
   2228   8018  Vladimir 
   2229   8018  Vladimir 	p)	pflag=1
   2230   8018  Vladimir 		codemgr_parent=$OPTARG;;
   2231   8018  Vladimir 
   2232   8018  Vladimir 	t)	tflag=1
   2233   8018  Vladimir 		remote_target=$OPTARG;;
   2234   8018  Vladimir 
   2235   8018  Vladimir 	U)	Uflag=1;;
   2236   8018  Vladimir 
   2237   8018  Vladimir 	w)	wflag=1;;
   2238   3252        dp 
   2239   3252        dp 	?)	usage;;
   2240   3252        dp 	esac
   2241   3252        dp done
   2242   3252        dp 
   2243   3252        dp FLIST=/tmp/$$.flist
   2244   3252        dp 
   2245   3252        dp if [[ -n $wflag && -n $lflag ]]; then
   2246   3252        dp 	usage
   2247   8018  Vladimir fi
   2248   8018  Vladimir 
   2249   8018  Vladimir # more sanity checking
   2250   8018  Vladimir if [[ -n $nflag && -z $Uflag ]]; then
   2251   8365  Vladimir 	print "it does not make sense to skip webrev generation" \
   2252   8365  Vladimir 	    "without -U"
   2253   8018  Vladimir 	exit 1
   2254   8018  Vladimir fi
   2255   8018  Vladimir 
   2256   8365  Vladimir if [[ -n $tflag && -z $Uflag && -z $Dflag ]]; then
   2257   8365  Vladimir 	echo "remote target has to be used only for upload or delete"
   2258   8018  Vladimir 	exit 1
   2259   9193      Mark fi
   2260   9193      Mark 
   2261   9193      Mark #
   2262   9420      Mark # For the invocation "webrev -n -U" with no other options, webrev will assume
   2263   9420      Mark # that the webrev exists in ${CWS}/webrev, but will upload it using the name
   2264   9420      Mark # $(basename ${CWS}).  So we need to get CWS set before we skip any remaining
   2265   9420      Mark # logic.
   2266   9420      Mark #
   2267   9420      Mark $WHICH_SCM | read SCM_MODE junk || exit 1
   2268   9420      Mark if [[ $SCM_MODE == "teamware" ]]; then
   2269   9420      Mark 	#
   2270   9420      Mark 	# Teamware priorities:
   2271   9420      Mark 	# 1. CODEMGR_WS from the environment
   2272   9420      Mark 	# 2. workspace name
   2273   9420      Mark 	#
   2274   9420      Mark 	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && codemgr_ws=$CODEMGR_WS
   2275   9420      Mark 	if [[ -n $codemgr_ws && ! -d $codemgr_ws ]]; then
   2276   9420      Mark 		print -u2 "$codemgr_ws: no such workspace"
   2277   9420      Mark 		exit 1
   2278   9420      Mark 	fi
   2279   9420      Mark 	[[ -z $codemgr_ws ]] && codemgr_ws=$(workspace name)
   2280   9420      Mark 	codemgr_ws=$(cd $codemgr_ws;print $PWD)
   2281   9420      Mark 	CODEMGR_WS=$codemgr_ws
   2282   9420      Mark 	CWS=$codemgr_ws
   2283   9420      Mark elif [[ $SCM_MODE == "mercurial" ]]; then
   2284   9420      Mark 	#
   2285   9420      Mark 	# Mercurial priorities:
   2286   9420      Mark 	# 1. hg root from CODEMGR_WS environment variable
   2287   9420      Mark 	# 2. hg root from directory of invocation
   2288   9420      Mark 	#
   2289   9420      Mark 	[[ -z $codemgr_ws && -n $CODEMGR_WS ]] && \
   2290   9420      Mark 	    codemgr_ws=$(hg root -R $CODEMGR_WS 2>/dev/null)
   2291   9420      Mark 	[[ -z $codemgr_ws ]] && codemgr_ws=$(hg root 2>/dev/null)
   2292   9420      Mark 	CWS=$codemgr_ws
   2293   9420      Mark elif [[ $SCM_MODE == "subversion" ]]; then
   2294   9420      Mark 	#
   2295   9420      Mark 	# Subversion priorities:
   2296   9420      Mark 	# 1. CODEMGR_WS from environment
   2297   9420      Mark 	# 2. Relative path from current directory to SVN repository root
   2298   9420      Mark 	#
   2299   9420      Mark 	if [[ -n $CODEMGR_WS && -d $CODEMGR_WS/.svn ]]; then
   2300   9420      Mark 		CWS=$CODEMGR_WS
   2301   9420      Mark 	else
   2302   9420      Mark 		svn info | while read line; do
   2303   9420      Mark 			if [[ $line == "URL: "* ]]; then
   2304   9420      Mark 				url=${line#URL: }
   2305   9420      Mark 			elif [[ $line == "Repository Root: "* ]]; then
   2306   9420      Mark 				repo=${line#Repository Root: }
   2307   9420      Mark 			fi
   2308   9420      Mark 		done
   2309   9420      Mark 
   2310  10789    Edward 		rel=${url#$repo}
   2311   9420      Mark 		CWS=${PWD%$rel}
   2312   9420      Mark 	fi
   2313   9420      Mark fi
   2314   9420      Mark 
   2315   9420      Mark #
   2316   9420      Mark # If no SCM has been determined, take either the environment setting
   2317   9420      Mark # setting for CODEMGR_WS, or the current directory if that wasn't set.
   2318   9420      Mark #
   2319   9420      Mark if [[ -z ${CWS} ]]; then
   2320   9420      Mark 	CWS=${CODEMGR_WS:-.}
   2321   9420      Mark fi
   2322   9420      Mark 
   2323   9420      Mark 
   2324   9420      Mark 
   2325   9420      Mark #
   2326   9193      Mark # If the command line options indicate no webrev generation, either
   2327   9193      Mark # explicitly (-n) or implicitly (-D but not -U), then there's a whole
   2328   9193      Mark # ton of logic we can skip.
   2329   9193      Mark #
   2330   9193      Mark # Instead of increasing indentation, we intentionally leave this loop
   2331   9193      Mark # body open here, and exit via break from multiple points within.
   2332   9193      Mark # Search for DO_EVERYTHING below to find the break points and closure.
   2333   9193      Mark #
   2334   9193      Mark for do_everything in 1; do
   2335   9193      Mark 
   2336   9193      Mark # DO_EVERYTHING: break point
   2337   9193      Mark if [[ -n $nflag || ( -z $Uflag && -n $Dflag ) ]]; then
   2338   9193      Mark 	break
   2339      0    stevel fi
   2340      0    stevel 
   2341   3252        dp #
   2342   3252        dp # If this manually set as the parent, and it appears to be an earlier webrev,
   2343   3252        dp # then note that fact and set the parent to the raw_files/new subdirectory.
   2344   3252        dp #
   2345   3252        dp if [[ -n $pflag && -d $codemgr_parent/raw_files/new ]]; then
   2346   3252        dp 	parent_webrev="$codemgr_parent"
   2347   3252        dp 	codemgr_parent="$codemgr_parent/raw_files/new"
   2348      0    stevel fi
   2349      0    stevel 
   2350   3252        dp if [[ -z $wflag && -z $lflag ]]; then
   2351   3252        dp 	shift $(($OPTIND - 1))
   2352      0    stevel 
   2353   3252        dp 	if [[ $1 == "-" ]]; then
   2354   3252        dp 		cat > $FLIST
   2355   3295        dp 		flist_mode="stdin"
   2356   3295        dp 		flist_done=1
   2357   3295        dp 		shift
   2358   3252        dp 	elif [[ -n $1 ]]; then
   2359   3295        dp 		if [[ ! -r $1 ]]; then
   2360   3252        dp 			print -u2 "$1: no such file or not readable"
   2361   3252        dp 			usage
   2362   3252        dp 		fi
   2363   3252        dp 		cat $1 > $FLIST
   2364   3295        dp 		flist_mode="file"
   2365   3295        dp 		flist_file=$1
   2366   3295        dp 		flist_done=1
   2367   3295        dp 		shift
   2368   3252        dp 	else
   2369   3295        dp 		flist_mode="auto"
   2370      0    stevel 	fi
   2371      0    stevel fi
   2372      0    stevel 
   2373   3252        dp #
   2374   3252        dp # Before we go on to further consider -l and -w, work out which SCM we think
   2375   3252        dp # is in use.
   2376   3252        dp #
   2377   7078  mjnelson case "$SCM_MODE" in
   2378   7078  mjnelson teamware|mercurial|subversion)
   2379   7078  mjnelson 	;;
   2380   7078  mjnelson unknown)
   2381   7078  mjnelson 	if [[ $flist_mode == "auto" ]]; then
   2382   7078  mjnelson 		print -u2 "Unable to determine SCM in use and file list not specified"
   2383   7078  mjnelson 		print -u2 "See which_scm(1) for SCM detection information."
   2384   7078  mjnelson 		exit 1
   2385   7078  mjnelson 	fi
   2386   7078  mjnelson 	;;
   2387   7078  mjnelson *)
   2388   7078  mjnelson 	if [[ $flist_mode == "auto" ]]; then
   2389   7078  mjnelson 		print -u2 "Unsupported SCM in use ($SCM_MODE) and file list not specified"
   2390   7078  mjnelson 		exit 1
   2391   7078  mjnelson 	fi
   2392   7078  mjnelson 	;;
   2393   7078  mjnelson esac
   2394      0    stevel 
   2395   3252        dp print -u2 "   SCM detected: $SCM_MODE"
   2396      0    stevel 
   2397   3252        dp if [[ -n $lflag ]]; then
   2398   3252        dp 	#
   2399   3252        dp 	# If the -l flag is given instead of the name of a file list,
   2400   3252        dp 	# then generate the file list by extracting file names from a
   2401   3252        dp 	# putback -n.
   2402   3252        dp 	#
   2403   3252        dp 	shift $(($OPTIND - 1))
   2404   7078  mjnelson 	if [[ $SCM_MODE == "teamware" ]]; then
   2405   7078  mjnelson 		flist_from_teamware "$*"
   2406   7078  mjnelson 	else
   2407   7078  mjnelson 		print -u2 -- "Error: -l option only applies to TeamWare"
   2408   7078  mjnelson 		exit 1
   2409   7078  mjnelson 	fi
   2410   3252        dp 	flist_done=1
   2411   3252        dp 	shift $#
   2412   3252        dp elif [[ -n $wflag ]]; then
   2413   3252        dp 	#
   2414   3252        dp 	# If the -w is given then assume the file list is in Bonwick's "wx"
   2415   3252        dp 	# command format, i.e.  pathname lines alternating with SCCS comment
   2416   3252        dp 	# lines with blank lines as separators.  Use the SCCS comments later
   2417   3252        dp 	# in building the index.html file.
   2418   3252        dp 	#
   2419   3252        dp 	shift $(($OPTIND - 1))
   2420   3252        dp 	wxfile=$1
   2421   3252        dp 	if [[ -z $wxfile && -n $CODEMGR_WS ]]; then
   2422   3252        dp 		if [[ -r $CODEMGR_WS/wx/active ]]; then
   2423   3252        dp 			wxfile=$CODEMGR_WS/wx/active
   2424   3252        dp 		fi
   2425   3252        dp 	fi
   2426   3252        dp 
   2427   3252        dp 	[[ -z $wxfile ]] && print -u2 "wx file not specified, and could not " \
   2428   3252        dp 	    "be auto-detected (check \$CODEMGR_WS)" && exit 1
   2429   7078  mjnelson 
   2430   7078  mjnelson 	if [[ ! -r $wxfile ]]; then
   2431   7078  mjnelson 		print -u2 "$wxfile: no such file or not readable"
   2432   7078  mjnelson 		usage
   2433   7078  mjnelson 	fi
   2434   3252        dp 
   2435   3252        dp 	print -u2 " File list from: wx 'active' file '$wxfile' ... \c"
   2436   3252        dp 	flist_from_wx $wxfile
   2437   3252        dp 	flist_done=1
   2438   3252        dp 	if [[ -n "$*" ]]; then
   2439   3252        dp 		shift
   2440   3252        dp 	fi
   2441   3295        dp elif [[ $flist_mode == "stdin" ]]; then
   2442   3295        dp 	print -u2 " File list from: standard input"
   2443   3295        dp elif [[ $flist_mode == "file" ]]; then
   2444   3295        dp 	print -u2 " File list from: $flist_file"
   2445      0    stevel fi
   2446      0    stevel 
   2447   3252        dp if [[ $# -gt 0 ]]; then
   2448   3295        dp 	print -u2 "WARNING: unused arguments: $*"
   2449      0    stevel fi
   2450      0    stevel 
   2451   9420      Mark #
   2452   9420      Mark # Before we entered the DO_EVERYTHING loop, we should have already set CWS
   2453   9420      Mark # and CODEMGR_WS as needed.  Here, we set the parent workspace.
   2454   9420      Mark #
   2455   9420      Mark 
   2456   3252        dp if [[ $SCM_MODE == "teamware" ]]; then
   2457   9420      Mark 
   2458   3252        dp 	#
   2459   9420      Mark 	# Teamware priorities:
   2460   3252        dp 	#
   2461   9420      Mark 	#      1) via -p command line option
   2462   3252        dp 	#      2) in the user environment
   2463   3252        dp 	#      3) in the flist
   2464   9420      Mark 	#      4) automatically based on the workspace
   2465   3252        dp 	#
   2466   3252        dp 
   2467   3252        dp 	#
   2468   9420      Mark 	# For 1, codemgr_parent will already be set.  Here's 2:
   2469   3252        dp 	#
   2470   3252        dp 	[[ -z $codemgr_parent && -n $CODEMGR_PARENT ]] && \
   2471   3252        dp 	    codemgr_parent=$CODEMGR_PARENT
   2472   3252        dp 	if [[ -n $codemgr_parent && ! -d $codemgr_parent ]]; then
   2473   3252        dp 		print -u2 "$codemgr_parent: no such directory"
   2474   3252        dp 		exit 1
   2475   3252        dp 	fi
   2476   3252        dp 
   2477   3252        dp 	#
   2478   3252        dp 	# If we're in auto-detect mode and we haven't already gotten the file
   2479   3252        dp 	# list, then see if we can get it by probing for wx.
   2480   3252        dp 	#
   2481   3295        dp 	if [[ -z $flist_done && $flist_mode == "auto" && -n $codemgr_ws ]]; then
   2482   3295        dp 		if [[ ! -x $WX ]]; then
   2483   3295        dp 			print -u2 "WARNING: wx not found!"
   2484   3252        dp 		fi
   2485   3252        dp 
   2486   3252        dp 		#
   2487   3252        dp 		# We need to use wx list -w so that we get renamed files, etc.
   2488   3252        dp 		# but only if a wx active file exists-- otherwise wx will
   2489   3252        dp 		# hang asking us to initialize our wx information.
   2490   3252        dp 		#
   2491   3295        dp 		if [[ -x $WX && -f $codemgr_ws/wx/active ]]; then
   2492   3252        dp 			print -u2 " File list from: 'wx list -w' ... \c"
   2493   3252        dp 			$WX list -w > $FLIST
   2494   3252        dp 			$WX comments > /tmp/$$.wx_comments
   2495   3252        dp 			wxfile=/tmp/$$.wx_comments
   2496   3252        dp 			print -u2 "done"
   2497   3252        dp 			flist_done=1
   2498   3252        dp 		fi
   2499   3252        dp 	fi
   2500   3252        dp 
   2501   3252        dp 	#
   2502   3252        dp 	# If by hook or by crook we've gotten a file list by now (perhaps
   2503   3252        dp 	# from the command line), eval it to extract environment variables from
   2504   9420      Mark 	# it: This is method 3 for finding the parent.
   2505   3252        dp 	#
   2506   3252        dp 	if [[ -z $flist_done ]]; then
   2507   3252        dp 		flist_from_teamware
   2508   3252        dp 	fi
   2509   9420      Mark 	env_from_flist
   2510   3252        dp 
   2511   3252        dp 	#
   2512   3252        dp 	# (4) If we still don't have a value for codemgr_parent, get it
   2513   3252        dp 	# from workspace.
   2514   3252        dp 	#
   2515   3252        dp 	[[ -z $codemgr_parent ]] && codemgr_parent=`workspace parent`
   2516   3252        dp 	if [[ ! -d $codemgr_parent ]]; then
   2517   3252        dp 		print -u2 "$CODEMGR_PARENT: no such parent workspace"
   2518   3252        dp 		exit 1
   2519   3252        dp 	fi
   2520   3252        dp 
   2521   3252        dp 	PWS=$codemgr_parent
   2522   7078  mjnelson 
   2523   7078  mjnelson 	[[ -n $parent_webrev ]] && RWS=$(workspace parent $CWS)
   2524   7078  mjnelson 
   2525   7078  mjnelson elif [[ $SCM_MODE == "mercurial" ]]; then
   2526   7078  mjnelson 	#
   2527   7078  mjnelson 	# Parent can either be specified with -p
   2528   7078  mjnelson 	# Specified with CODEMGR_PARENT in the environment
   2529   7078  mjnelson 	# or taken from hg's default path.
   2530   7078  mjnelson 	#
   2531   7078  mjnelson 
   2532   7078  mjnelson 	if [[ -z $codemgr_parent && -n $CODEMGR_PARENT ]]; then
   2533   7078  mjnelson 		codemgr_parent=$CODEMGR_PARENT
   2534   7078  mjnelson 	fi
   2535   7078  mjnelson 
   2536   7078  mjnelson 	if [[ -z $codemgr_parent ]]; then
   2537   7078  mjnelson 		codemgr_parent=`hg path -R $codemgr_ws default 2>/dev/null`
   2538   7078  mjnelson 	fi
   2539   7078  mjnelson 
   2540   7078  mjnelson 	CWS_REV=`hg parent -R $codemgr_ws --template '{node|short}' 2>/dev/null`
   2541   7078  mjnelson 	PWS=$codemgr_parent
   2542   7078  mjnelson 
   2543  10789    Edward 	#
   2544   7078  mjnelson 	# If the parent is a webrev, we want to do some things against
   2545   7078  mjnelson 	# the natural workspace parent (file list, comments, etc)
   2546   7078  mjnelson 	#
   2547   7078  mjnelson 	if [[ -n $parent_webrev ]]; then
   2548   7078  mjnelson 		real_parent=$(hg path -R $codemgr_ws default 2>/dev/null)
   2549   7078  mjnelson 	else
   2550   7078  mjnelson 		real_parent=$PWS
   2551   7078  mjnelson 	fi
   2552   7078  mjnelson 
   2553   7078  mjnelson 	#
   2554   7078  mjnelson 	# If hg-active exists, then we run it.  In the case of no explicit
   2555   7078  mjnelson 	# flist given, we'll use it for our comments.  In the case of an
   2556   7078  mjnelson 	# explicit flist given we'll try to use it for comments for any
   2557   7078  mjnelson 	# files mentioned in the flist.
   2558   7078  mjnelson 	#
   2559   7078  mjnelson 	if [[ -z $flist_done ]]; then
   2560   7078  mjnelson 		flist_from_mercurial $CWS $real_parent
   2561   7078  mjnelson 		flist_done=1
   2562   7078  mjnelson 	fi
   2563   7078  mjnelson 
   2564   7078  mjnelson 	#
   2565   7078  mjnelson 	# If we have a file list now, pull out any variables set
   2566   7078  mjnelson 	# therein.  We do this now (rather than when we possibly use
   2567   7078  mjnelson 	# hg-active to find comments) to avoid stomping specifications
   2568   7078  mjnelson 	# in the user-specified flist.
   2569  10789    Edward 	#
   2570   7078  mjnelson 	if [[ -n $flist_done ]]; then
   2571   7078  mjnelson 		env_from_flist
   2572   7078  mjnelson 	fi
   2573   7078  mjnelson 
   2574   7078  mjnelson 	#
   2575   7078  mjnelson 	# Only call hg-active if we don't have a wx formatted file already
   2576   7078  mjnelson 	#
   2577   7078  mjnelson 	if [[ -x $HG_ACTIVE && -z $wxfile ]]; then
   2578   7078  mjnelson 		print "  Comments from: hg-active -p $real_parent ...\c"
   2579   7078  mjnelson 		hg_active_wxfile $CWS $real_parent
   2580   7078  mjnelson 		print " Done."
   2581   7078  mjnelson 	fi
   2582  10789    Edward 
   2583   7078  mjnelson 	#
   2584   7078  mjnelson 	# At this point we must have a wx flist either from hg-active,
   2585   7078  mjnelson 	# or in general.  Use it to try and find our parent revision,
   2586   7078  mjnelson 	# if we don't have one.
   2587   7078  mjnelson 	#
   2588   7078  mjnelson 	if [[ -z $HG_PARENT ]]; then
   2589   9079  Vladimir 		eval `$SED -e "s/#.*$//" $wxfile | $GREP HG_PARENT=`
   2590   7078  mjnelson 	fi
   2591   7078  mjnelson 
   2592   7078  mjnelson 	#
   2593   7078  mjnelson 	# If we still don't have a parent, we must have been given a
   2594   7078  mjnelson 	# wx-style active list with no HG_PARENT specification, run
   2595   7078  mjnelson 	# hg-active and pull an HG_PARENT out of it, ignore the rest.
   2596   7078  mjnelson 	#
   2597   7078  mjnelson 	if [[ -z $HG_PARENT && -x $HG_ACTIVE ]]; then
   2598   7078  mjnelson 		$HG_ACTIVE -w $codemgr_ws -p $real_parent | \
   2599   9079  Vladimir 		    eval `$SED -e "s/#.*$//" | $GREP HG_PARENT=`
   2600   7078  mjnelson 	elif [[ -z $HG_PARENT ]]; then
   2601   7078  mjnelson 		print -u2 "Error: Cannot discover parent revision"
   2602   7078  mjnelson 		exit 1
   2603   7078  mjnelson 	fi
   2604   7078  mjnelson elif [[ $SCM_MODE == "subversion" ]]; then
   2605   7078  mjnelson 
   2606   7078  mjnelson 	#
   2607   7078  mjnelson 	# We only will have a real parent workspace in the case one
   2608   7078  mjnelson 	# was specified (be it an older webrev, or another checkout).
   2609   7078  mjnelson 	#
   2610   7078  mjnelson 	[[ -n $codemgr_parent ]] && PWS=$codemgr_parent
   2611   7078  mjnelson 
   2612   7078  mjnelson 	if [[ -z $flist_done && $flist_mode == "auto" ]]; then
   2613   7078  mjnelson 		flist_from_subversion $CWS $OLDPWD
   2614   7078  mjnelson 	fi
   2615   7078  mjnelson else
   2616   7078  mjnelson     if [[ $SCM_MODE == "unknown" ]]; then
   2617   7078  mjnelson 	print -u2 "    Unknown type of SCM in use"
   2618   7078  mjnelson     else
   2619   7078  mjnelson 	print -u2 "    Unsupported SCM in use: $SCM_MODE"
   2620   7078  mjnelson     fi
   2621   7078  mjnelson 
   2622   7078  mjnelson     env_from_flist
   2623   7078  mjnelson 
   2624   7078  mjnelson     if [[ -z $CODEMGR_WS ]]; then
   2625   7078  mjnelson 	print -u2 "SCM not detected/supported and CODEMGR_WS not specified"
   2626   7078  mjnelson 	exit 1
   2627   7078  mjnelson     fi
   2628   7078  mjnelson 
   2629   7078  mjnelson     if [[ -z $CODEMGR_PARENT ]]; then
   2630   7078  mjnelson 	print -u2 "SCM not detected/supported and CODEMGR_PARENT not specified"
   2631   7078  mjnelson 	exit 1
   2632   7078  mjnelson     fi
   2633   7078  mjnelson 
   2634   7078  mjnelson     CWS=$CODEMGR_WS
   2635   7078  mjnelson     PWS=$CODEMGR_PARENT
   2636      0    stevel fi
   2637      0    stevel 
   2638   3252        dp #
   2639   3252        dp # If the user didn't specify a -i option, check to see if there is a
   2640   3252        dp # webrev-info file in the workspace directory.
   2641   3252        dp #
   2642   3252        dp if [[ -z $iflag && -r "$CWS/webrev-info" ]]; then
   2643   3252        dp 	iflag=1
   2644   3252        dp 	INCLUDE_FILE="$CWS/webrev-info"
   2645      0    stevel fi
   2646      0    stevel 
   2647   3252        dp if [[ -n $iflag ]]; then
   2648   3252        dp 	if [[ ! -r $INCLUDE_FILE ]]; then
   2649   3252        dp 		print -u2 "include file '$INCLUDE_FILE' does not exist or is" \
   2650   3252        dp 		    "not readable."
   2651   3252        dp 		exit 1
   2652   3252        dp 	else
   2653   3252        dp 		#
   2654   3252        dp 		# $INCLUDE_FILE may be a relative path, and the script alters
   2655   3252        dp 		# PWD, so we just stash a copy in /tmp.
   2656   3252        dp 		#
   2657   3252        dp 		cp $INCLUDE_FILE /tmp/$$.include
   2658   3252        dp 	fi
   2659      0    stevel fi
   2660      0    stevel 
   2661   9193      Mark # DO_EVERYTHING: break point
   2662   9193      Mark if [[ -n $Nflag ]]; then
   2663   9193      Mark 	break
   2664   9193      Mark fi
   2665   9193      Mark 
   2666   9193      Mark typeset -A itsinfo
   2667   9193      Mark typeset -r its_sed_script=/tmp/$$.its_sed
   2668   9193      Mark valid_prefixes=
   2669   9193      Mark if [[ -z $nflag ]]; then
   2670   9193      Mark 	DEFREGFILE="$(dirname $(whence $0))/../etc/its.reg"
   2671   9193      Mark 	if [[ -n $Iflag ]]; then
   2672   9193      Mark 		REGFILE=$ITSREG
   2673   9193      Mark 	elif [[ -r $HOME/.its.reg ]]; then
   2674   9193      Mark 		REGFILE=$HOME/.its.reg
   2675   9193      Mark 	else
   2676   9193      Mark 		REGFILE=$DEFREGFILE
   2677   9193      Mark 	fi
   2678   9193      Mark 	if [[ ! -r $REGFILE ]]; then
   2679   9193      Mark 		print "ERROR: Unable to read database registry file $REGFILE"
   2680   9193      Mark 		exit 1
   2681   9193      Mark 	elif [[ $REGFILE != $DEFREGFILE ]]; then
   2682   9193      Mark 		print "   its.reg from: $REGFILE"
   2683   9193      Mark 	fi
   2684   9193      Mark 
   2685   9193      Mark 	$SED -e '/^#/d' -e '/^[ 	]*$/d' $REGFILE | while read LINE; do
   2686  10789    Edward 
   2687   9193      Mark 		name=${LINE%%=*}
   2688   9193      Mark 		value="${LINE#*=}"
   2689   9193      Mark 
   2690   9193      Mark 		if [[ $name == PREFIX ]]; then
   2691   9193      Mark 			p=${value}
   2692   9193      Mark 			valid_prefixes="${p} ${valid_prefixes}"
   2693   9193      Mark 		else
   2694   9193      Mark 			itsinfo["${p}_${name}"]="${value}"
   2695   9193      Mark 		fi
   2696   9193      Mark 	done
   2697   9193      Mark 
   2698   9193      Mark 
   2699   9193      Mark 	DEFCONFFILE="$(dirname $(whence $0))/../etc/its.conf"
   2700   9193      Mark 	CONFFILES=$DEFCONFFILE
   2701   9193      Mark 	if [[ -r $HOME/.its.conf ]]; then
   2702   9193      Mark 		CONFFILES="${CONFFILES} $HOME/.its.conf"
   2703   9193      Mark 	fi
   2704   9193      Mark 	if [[ -n $Cflag ]]; then
   2705   9193      Mark 		CONFFILES="${CONFFILES} ${ITSCONF}"
   2706   9193      Mark 	fi
   2707   9193      Mark 	its_domain=
   2708   9193      Mark 	its_priority=
   2709   9193      Mark 	for cf in ${CONFFILES}; do
   2710   9193      Mark 		if [[ ! -r $cf ]]; then
   2711   9193      Mark 			print "ERROR: Unable to read database configuration file $cf"
   2712   9193      Mark 			exit 1
   2713   9193      Mark 		elif [[ $cf != $DEFCONFFILE ]]; then
   2714   9193      Mark 			print "       its.conf: reading $cf"
   2715   9193      Mark 		fi
   2716   9193      Mark 		$SED -e '/^#/d' -e '/^[ 	]*$/d' $cf | while read LINE; do
   2717   9193      Mark 		    eval "${LINE}"
   2718   9193      Mark 		done
   2719   9193      Mark 	done
   2720   9193      Mark 
   2721   9193      Mark 	#
   2722   9193      Mark 	# If an information tracking system is explicitly identified by prefix,
   2723   9193      Mark 	# we want to disregard the specified priorities and resolve it accordingly.
   2724   9193      Mark 	#
   2725   9193      Mark 	# To that end, we'll build a sed script to do each valid prefix in turn.
   2726   9193      Mark 	#
   2727   9193      Mark 	for p in ${valid_prefixes}; do
   2728   9193      Mark 		#
   2729   9193      Mark 		# When an informational URL was provided, translate it to a
   2730   9193      Mark 		# hyperlink.  When omitted, simply use the prefix text.
   2731   9193      Mark 		#
   2732   9193      Mark 		if [[ -z ${itsinfo["${p}_INFO"]} ]]; then
   2733   9193      Mark 			itsinfo["${p}_INFO"]=${p}
   2734   9193      Mark 		else
   2735   9193      Mark 			itsinfo["${p}_INFO"]="<a href=\\\"${itsinfo["${p}_INFO"]}\\\">${p}</a>"
   2736   9193      Mark 		fi
   2737   9193      Mark 
   2738   9193      Mark 		#
   2739   9193      Mark 		# Assume that, for this invocation of webrev, all references
   2740   9193      Mark 		# to this information tracking system should resolve through
   2741   9193      Mark 		# the same URL.
   2742   9193      Mark 		#
   2743   9193      Mark 		# If the caller specified -O, then always use EXTERNAL_URL.
   2744   9193      Mark 		#
   2745   9193      Mark 		# Otherwise, look in the list of domains for a matching
   2746   9193      Mark 		# INTERNAL_URL.
   2747   9193      Mark 		#
   2748   9193      Mark 		[[ -z $Oflag ]] && for d in ${its_domain}; do
   2749   9193      Mark 			if [[ -n ${itsinfo["${p}_INTERNAL_URL_${d}"]} ]]; then
   2750   9193      Mark 				itsinfo["${p}_URL"]="${itsinfo[${p}_INTERNAL_URL_${d}]}"
   2751   9193      Mark 				break
   2752   9193      Mark 			fi
   2753   9193      Mark 		done
   2754   9193      Mark 		if [[ -z ${itsinfo["${p}_URL"]} ]]; then
   2755   9193      Mark 			itsinfo["${p}_URL"]="${itsinfo[${p}_EXTERNAL_URL]}"
   2756   9193      Mark 		fi
   2757   9193      Mark 
   2758   9193      Mark 		#
   2759   9193      Mark 		# Turn the destination URL into a hyperlink
   2760   9193      Mark 		#
   2761   9193      Mark 		itsinfo["${p}_URL"]="<a href=\\\"${itsinfo[${p}_URL]}\\\">&</a>"
   2762   9193      Mark 
   2763   9193      Mark 		print "/^${p}[ 	]/ {
   2764   9193      Mark 				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
   2765   9193      Mark 				s;^${p};${itsinfo[${p}_INFO]};
   2766   9193      Mark 			}" >> ${its_sed_script}
   2767   9193      Mark 	done
   2768   9193      Mark 
   2769   9193      Mark 	#
   2770   9193      Mark 	# The previous loop took care of explicit specification.  Now use
   2771   9193      Mark 	# the configured priorities to attempt implicit translations.
   2772   9193      Mark 	#
   2773   9193      Mark 	for p in ${its_priority}; do
   2774   9193      Mark 		print "/^${itsinfo[${p}_REGEX]}[ 	]/ {
   2775   9193      Mark 				s;${itsinfo[${p}_REGEX]};${itsinfo[${p}_URL]};g
   2776   9193      Mark 			}" >> ${its_sed_script}
   2777   9193      Mark 	done
   2778   9193      Mark fi
   2779   9193      Mark 
   2780   9193      Mark #
   2781   9193      Mark # Search for DO_EVERYTHING above for matching "for" statement
   2782   9193      Mark # and explanation of this terminator.
   2783   9193      Mark #
   2784   9193      Mark done
   2785   9193      Mark 
   2786   3252        dp #
   2787   3252        dp # Output directory.
   2788   3252        dp #
   2789   3252        dp WDIR=${WDIR:-$CWS/webrev}
   2790      0    stevel 
   2791   3252        dp #
   2792   8018  Vladimir # Name of the webrev, derived from the workspace name or output directory;
   2793   8018  Vladimir # in the future this could potentially be an option.
   2794   3252        dp #
   2795   8018  Vladimir if [[ -n $oflag ]]; then
   2796   8018  Vladimir 	WNAME=${WDIR##*/}
   2797   8018  Vladimir else
   2798   8018  Vladimir 	WNAME=${CWS##*/}
   2799   8018  Vladimir fi
   2800   8018  Vladimir 
   2801   8365  Vladimir # Make sure remote target is well formed for remote upload/delete.
   2802   8365  Vladimir if [[ -n $Dflag || -n $Uflag ]]; then
   2803   9079  Vladimir 	#
   2804   8365  Vladimir 	# If remote target is not specified, build it from scratch using
   2805   8365  Vladimir 	# the default values.
   2806   9079  Vladimir 	#
   2807   8365  Vladimir 	if [[ -z $tflag ]]; then
   2808   8365  Vladimir 		remote_target=${DEFAULT_REMOTE_HOST}:${WNAME}
   2809   8365  Vladimir 	else
   2810   9079  Vladimir 		#
   2811   9079  Vladimir 		# Check upload target prefix first.
   2812   9079  Vladimir 		#
   2813   9079  Vladimir 		if [[ "${remote_target}" != ${rsync_prefix}* &&
   2814   9079  Vladimir 		    "${remote_target}" != ${ssh_prefix}* ]]; then
   2815   9079  Vladimir 			print "ERROR: invalid prefix of upload URI" \
   2816   9079  Vladimir 			    "($remote_target)"
   2817   9079  Vladimir 			exit 1
   2818   9079  Vladimir 		fi
   2819   9079  Vladimir 		#
   2820   8365  Vladimir 		# If destination specification is not in the form of
   2821   8365  Vladimir 		# host_spec:remote_dir then assume it is just remote hostname
   2822   8365  Vladimir 		# and append a colon and destination directory formed from
   2823   8365  Vladimir 		# local webrev directory name.
   2824   9079  Vladimir 		#
   2825   9079  Vladimir 		typeset target_no_prefix=${remote_target##*://}
   2826   9079  Vladimir 		if [[ ${target_no_prefix} == *:* ]]; then
   2827   8365  Vladimir 			if [[ "${remote_target}" == *: ]]; then
   2828   9079  Vladimir 				remote_target=${remote_target}${WNAME}
   2829   9079  Vladimir 			fi
   2830   9079  Vladimir 		else
   2831   9079  Vladimir 			if [[ ${target_no_prefix} == */* ]]; then
   2832   9079  Vladimir 				print "ERROR: badly formed upload URI" \
   2833   9079  Vladimir 					"($remote_target)"
   2834   9079  Vladimir 				exit 1
   2835   8365  Vladimir 			else
   2836   9079  Vladimir 				remote_target=${remote_target}:${WNAME}
   2837   8365  Vladimir 			fi
   2838   8365  Vladimir 		fi
   2839   8365  Vladimir 	fi
   2840   9079  Vladimir 
   2841   9079  Vladimir 	#
   2842   9079  Vladimir 	# Strip trailing slash. Each upload method will deal with directory
   2843   9079  Vladimir 	# specification separately.
   2844   9079  Vladimir 	#
   2845   9079  Vladimir 	remote_target=${remote_target%/}
   2846   8365  Vladimir fi
   2847   8365  Vladimir 
   2848   9079  Vladimir #
   2849   8365  Vladimir # Option -D by itself (option -U not present) implies no webrev generation.
   2850   9079  Vladimir #
   2851   8365  Vladimir if [[ -z $Uflag && -n $Dflag ]]; then
   2852   9079  Vladimir 	delete_webrev 1 1
   2853   8018  Vladimir 	exit $?
   2854   8365  Vladimir fi
   2855   8365  Vladimir 
   2856   9079  Vladimir #
   2857   8365  Vladimir # Do not generate the webrev, just upload it or delete it.
   2858   9079  Vladimir #
   2859   8365  Vladimir if [[ -n $nflag ]]; then
   2860   8365  Vladimir 	if [[ -n $Dflag ]]; then
   2861   9079  Vladimir 		delete_webrev 1 1
   2862   8365  Vladimir 		(( $? == 0 )) || exit $?
   2863   8365  Vladimir 	fi
   2864   8365  Vladimir 	if [[ -n $Uflag ]]; then
   2865   8365  Vladimir 		upload_webrev
   2866   8365  Vladimir 		exit $?
   2867   8365  Vladimir 	fi
   2868   8018  Vladimir fi
   2869   3252        dp 
   2870   5175      jmcp if [ "${WDIR%%/*}" ]; then
   2871      0    stevel 	WDIR=$PWD/$WDIR
   2872      0    stevel fi
   2873   3252        dp 
   2874   3252        dp if [[ ! -d $WDIR ]]; then
   2875   3252        dp 	mkdir -p $WDIR
   2876   8365  Vladimir 	(( $? != 0 )) && exit 1
   2877      0    stevel fi
   2878      0    stevel 
   2879   3252        dp #
   2880   3252        dp # Summarize what we're going to do.
   2881   3252        dp #
   2882   7078  mjnelson if [[ -n $CWS_REV ]]; then
   2883   7078  mjnelson 	print "      Workspace: $CWS (at $CWS_REV)"
   2884   7078  mjnelson else
   2885   7078  mjnelson 	print "      Workspace: $CWS"
   2886   7078  mjnelson fi
   2887   3252        dp if [[ -n $parent_webrev ]]; then
   2888   3252        dp 	print "Compare against: webrev at $parent_webrev"
   2889   3252        dp else
   2890   7078  mjnelson 	if [[ -n $HG_PARENT ]]; then
   2891   7078  mjnelson 		hg_parent_short=`echo $HG_PARENT \
   2892   9079  Vladimir 			| $SED -e 's/\([0-9a-f]\{12\}\).*/\1/'`
   2893   7078  mjnelson 		print "Compare against: $PWS (at $hg_parent_short)"
   2894   7078  mjnelson 	else
   2895   7078  mjnelson 		print "Compare against: $PWS"
   2896   7078  mjnelson 	fi
   2897      0    stevel fi
   2898      0    stevel 
   2899   3252        dp [[ -n $INCLUDE_FILE ]] && print "      Including: $INCLUDE_FILE"
   2900   3252        dp print "      Output to: $WDIR"
   2901      0    stevel 
   2902   3252        dp #
   2903   3252        dp # Save the file list in the webrev dir
   2904   3252        dp #
   2905   3252        dp [[ ! $FLIST -ef $WDIR/file.list ]] && cp $FLIST $WDIR/file.list
   2906   3252        dp 
   2907   3252        dp rm -f $WDIR/$WNAME.patch
   2908   3252        dp rm -f $WDIR/$WNAME.ps
   2909   3252        dp rm -f $WDIR/$WNAME.pdf
   2910   3252        dp 
   2911   3252        dp touch $WDIR/$WNAME.patch
   2912   3252        dp 
   2913   3252        dp print "   Output Files:"
   2914   3252        dp 
   2915   3252        dp #
   2916   3252        dp # Clean up the file list: Remove comments, blank lines and env variables.
   2917   3252        dp #
   2918   9079  Vladimir $SED -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST > /tmp/$$.flist.clean
   2919   3252        dp FLIST=/tmp/$$.flist.clean
   2920   7078  mjnelson 
   2921   7078  mjnelson #
   2922   7078  mjnelson # For Mercurial, create a cache of manifest entries.
   2923   7078  mjnelson #
   2924   7078  mjnelson if [[ $SCM_MODE == "mercurial" ]]; then
   2925   7078  mjnelson 	#
   2926   7078  mjnelson 	# Transform the FLIST into a temporary sed script that matches
   2927   7078  mjnelson 	# relevant entries in the Mercurial manifest as follows:
   2928   7078  mjnelson 	# 1) The script will be used against the parent revision manifest,
   2929   7078  mjnelson 	#    so for FLIST lines that have two filenames (a renamed file)
   2930   7078  mjnelson 	#    keep only the old name.
   2931   7078  mjnelson 	# 2) Escape all forward slashes the filename.
   2932   7078  mjnelson 	# 3) Change the filename into another sed command that matches
   2933   7078  mjnelson 	#    that file in "hg manifest -v" output:  start of line, three
   2934   7078  mjnelson 	#    octal digits for file permissions, space, a file type flag
   2935   7078  mjnelson 	#    character, space, the filename, end of line.
   2936  10789    Edward 	# 4) Eliminate any duplicate entries.  (This can occur if a
   2937  10789    Edward 	#    file has been used as the source of an hg cp and it's
   2938  10789    Edward 	#    also been modified in the same changeset.)
   2939   7078  mjnelson 	#
   2940   7078  mjnelson 	SEDFILE=/tmp/$$.manifest.sed
   2941   9079  Vladimir 	$SED '
   2942   7078  mjnelson 		s#^[^ ]* ##
   2943   7078  mjnelson 		s#/#\\\/#g
   2944   7078  mjnelson 		s#^.*$#/^... . &$/p#
   2945  10789    Edward 	' < $FLIST | $SORT -u > $SEDFILE
   2946   7078  mjnelson 
   2947   7078  mjnelson 	#
   2948   7078  mjnelson 	# Apply the generated script to the output of "hg manifest -v"
   2949   7078  mjnelson 	# to get the relevant subset for this webrev.
   2950   7078  mjnelson 	#
   2951   7078  mjnelson 	HG_PARENT_MANIFEST=/tmp/$$.manifest
   2952   7078  mjnelson 	hg -R $CWS manifest -v -r $HG_PARENT |
   2953   9079  Vladimir 	    $SED -n -f $SEDFILE > $HG_PARENT_MANIFEST
   2954   7078  mjnelson fi
   2955   3252        dp 
   2956   3252        dp #
   2957   3252        dp # First pass through the files: generate the per-file webrev HTML-files.
   2958   3252        dp #
   2959   3252        dp cat $FLIST | while read LINE
   2960      0    stevel do
   2961      0    stevel 	set - $LINE
   2962      0    stevel 	P=$1
   2963      0    stevel 
   2964   3252        dp 	#
   2965   3252        dp 	# Normally, each line in the file list is just a pathname of a
   2966   3252        dp 	# file that has been modified or created in the child.  A file
   2967   3252        dp 	# that is renamed in the child workspace has two names on the
   2968   3252        dp 	# line: new name followed by the old name.
   2969   3252        dp 	#
   2970   3252        dp 	oldname=""
   2971   3252        dp 	oldpath=""
   2972   3252        dp 	rename=
   2973   3252        dp 	if [[ $# -eq 2 ]]; then
   2974      0    stevel 		PP=$2			# old filename
   2975  10789    Edward 		if [[ -f $PP ]]; then
   2976  10789    Edward 			oldname=" (copied from $PP)"
   2977  10789    Edward 		else
   2978  10789    Edward 			oldname=" (renamed from $PP)"
   2979  10789    Edward 		fi
   2980   3252        dp 		oldpath="$PP"
   2981   3252        dp 		rename=1
   2982  10789    Edward 		PDIR=${PP%/*}
   2983  10789    Edward 		if [[ $PDIR == $PP ]]; then
   2984      0    stevel 			PDIR="."   # File at root of workspace
   2985      0    stevel 		fi
   2986      0    stevel 
   2987      0    stevel 		PF=${PP##*/}
   2988      0    stevel 
   2989  10789    Edward 		DIR=${P%/*}
   2990  10789    Edward 		if [[ $DIR == $P ]]; then
   2991      0    stevel 			DIR="."   # File at root of workspace
   2992      0    stevel 		fi
   2993   3252        dp 
   2994      0    stevel 		F=${P##*/}
   2995   3252        dp 
   2996      0    stevel         else
   2997  10789    Edward 		DIR=${P%/*}
   2998  10789    Edward 		if [[ "$DIR" == "$P" ]]; then
   2999      0    stevel 			DIR="."   # File at root of workspace
   3000      0    stevel 		fi
   3001   3252        dp 
   3002      0    stevel 		F=${P##*/}
   3003      0    stevel 
   3004      0    stevel 		PP=$P
   3005      0    stevel 		PDIR=$DIR
   3006      0    stevel 		PF=$F
   3007      0    stevel 	fi
   3008      0    stevel 
   3009   3252        dp 	COMM=`getcomments html $P $PP`
   3010      0    stevel 
   3011   3252        dp 	print "\t$P$oldname\n\t\t\c"
   3012      0    stevel 
   3013      0    stevel 	# Make the webrev mirror directory if necessary
   3014   3252        dp 	mkdir -p $WDIR/$DIR
   3015   3252        dp 
   3016   3252        dp 	#
   3017   3252        dp 	# If we're in OpenSolaris mode, we enforce a minor policy:
   3018   3252        dp 	# help to make sure the reviewer doesn't accidentally publish
   3019   5175      jmcp 	# source which is in usr/closed/* or deleted_files/usr/closed/*
   3020   3252        dp 	#
   3021   5175      jmcp 	if [[ -n "$Oflag" ]]; then
   3022   3252        dp 		pclosed=${P##usr/closed/}
   3023   5175      jmcp 		pdeleted=${P##deleted_files/usr/closed/}
   3024   5175      jmcp 		if [[ "$pclosed" != "$P" || "$pdeleted" != "$P" ]]; then
   3025   3252        dp 			print "*** Omitting closed source for OpenSolaris" \
   3026   3252        dp 			    "mode review"
   3027   3252        dp 			continue
   3028   3252        dp 		fi
   3029      0    stevel 	fi
   3030      0    stevel 
   3031   3252        dp 	#
   3032   7078  mjnelson 	# We stash old and new files into parallel directories in $WDIR
   3033   3252        dp 	# and do our diffs there.  This makes it possible to generate
   3034   3252        dp 	# clean looking diffs which don't have absolute paths present.
   3035   3252        dp 	#
   3036      0    stevel 
   3037   7078  mjnelson 	build_old_new "$WDIR" "$PWS" "$PDIR" "$PF" "$CWS" "$DIR" "$F" || \
   3038   7078  mjnelson 	    continue
   3039      0    stevel 
   3040   7078  mjnelson 	#
   3041   7078  mjnelson 	# Keep the old PWD around, so we can safely switch back after
   3042   7078  mjnelson 	# diff generation, such that build_old_new runs in a
   3043   7078  mjnelson 	# consistent environment.
   3044   7078  mjnelson 	#
   3045   7078  mjnelson 	OWD=$PWD
   3046   3252        dp 	cd $WDIR/raw_files
   3047   3252        dp 	ofile=old/$PDIR/$PF
   3048   3252        dp 	nfile=new/$DIR/$F
   3049      0    stevel 
   3050   3252        dp 	mv_but_nodiff=
   3051   3252        dp 	cmp $ofile $nfile > /dev/null 2>&1
   3052   3252        dp 	if [[ $? == 0 && $rename == 1 ]]; then
   3053   3252        dp 		mv_but_nodiff=1
   3054   3252        dp 	fi
   3055   3252        dp 
   3056   3252        dp 	#
   3057   3252        dp 	# If we have old and new versions of the file then run the appropriate
   3058   3252        dp 	# diffs.  This is complicated by a couple of factors:
   3059   3252        dp 	#
   3060   3252        dp 	#	- renames must be handled specially: we emit a 'remove'
   3061   3252        dp 	#	  diff and an 'add' diff
   3062   3252        dp 	#	- new files and deleted files must be handled specially
   3063   3252        dp 	#	- Solaris patch(1m) can't cope with file creation
   3064   3252        dp 	#	  (and hence renames) as of this writing.
   3065   3252        dp 	#       - To make matters worse, gnu patch doesn't interpret the
   3066   3252        dp 	#	  output of Solaris diff properly when it comes to
   3067   3252        dp 	#	  adds and deletes.  We need to do some "cleansing"
   3068   3252        dp 	#         transformations:
   3069  10789    Edward 	#	    [to add a file] @@ -1,0 +X,Y @@  -->  @@ -0,0 +X,Y @@
   3070   3252        dp 	#	    [to del a file] @@ -X,Y +1,0 @@  -->  @@ -X,Y +0,0 @@
   3071   3252        dp 	#
   3072   9079  Vladimir 	cleanse_rmfile="$SED 's/^\(@@ [0-9+,-]*\) [0-9+,-]* @@$/\1 +0,0 @@/'"
   3073   9079  Vladimir 	cleanse_newfile="$SED 's/^@@ [0-9+,-]* \([0-9+,-]* @@\)$/@@ -0,0 \1/'"
   3074   3252        dp 
   3075   3252        dp 	rm -f $WDIR/$DIR/$F.patch
   3076   3252        dp 	if [[ -z $rename ]]; then
   3077   5175      jmcp 		if [ ! -f "$ofile" ]; then
   3078   3252        dp 			diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
   3079   3252        dp 			    > $WDIR/$DIR/$F.patch
   3080   5175      jmcp 		elif [ ! -f "$nfile" ]; then
   3081   3252        dp 			diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
   3082   3252        dp 			    > $WDIR/$DIR/$F.patch
   3083   3252        dp 		else
   3084   3252        dp 			diff -u $ofile $nfile > $WDIR/$DIR/$F.patch
   3085   3252        dp 		fi
   3086   3252        dp 	else
   3087   3252        dp 		diff -u $ofile /dev/null | sh -c "$cleanse_rmfile" \
   3088   3252        dp 		    > $WDIR/$DIR/$F.patch
   3089   3252        dp 
   3090   3252        dp 		diff -u /dev/null $nfile | sh -c "$cleanse_newfile" \
   3091   3252        dp 		    >> $WDIR/$DIR/$F.patch
   3092   3252        dp 	fi
   3093   3252        dp 
   3094   3252        dp 	#
   3095   3252        dp 	# Tack the patch we just made onto the accumulated patch for the
   3096   3252        dp 	# whole wad.
   3097   3252        dp 	#
   3098   3252        dp 	cat $WDIR/$DIR/$F.patch >> $WDIR/$WNAME.patch
   3099   3252        dp 
   3100   3252        dp 	print " patch\c"
   3101   3252        dp 
   3102   3252        dp 	if [[ -f $ofile && -f $nfile && -z $mv_but_nodiff ]]; then
   3103   3252        dp 
   3104   3252        dp 		${CDIFFCMD:-diff -bt -C 5} $ofile $nfile > $WDIR/$DIR/$F.cdiff
   3105   3252        dp 		diff_to_html $F $DIR/$F "C" "$COMM" < $WDIR/$DIR/$F.cdiff \
   3106   3252        dp 		    > $WDIR/$DIR/$F.cdiff.html
   3107      0    stevel 		print " cdiffs\c"
   3108      0    stevel 
   3109   3252        dp 		${UDIFFCMD:-diff -bt -U 5} $ofile $nfile > $WDIR/$DIR/$F.udiff
   3110   3252        dp 		diff_to_html $F $DIR/$F "U" "$COMM" < $WDIR/$DIR/$F.udiff \
   3111   3252        dp 		    > $WDIR/$DIR/$F.udiff.html
   3112   3252        dp 
   3113      0    stevel 		print " udiffs\c"
   3114      0    stevel 
   3115      0    stevel 		if [[ -x $WDIFF ]]; then
   3116   3252        dp 			$WDIFF -c "$COMM" \
   3117   3252        dp 			    -t "$WNAME Wdiff $DIR/$F" $ofile $nfile > \
   3118   3252        dp 			    $WDIR/$DIR/$F.wdiff.html 2>/dev/null
   3119   3252        dp 			if [[ $? -eq 0 ]]; then
   3120   3252        dp 				print " wdiffs\c"
   3121   3252        dp 			else
   3122   3252        dp 				print " wdiffs[fail]\c"
   3123   3252        dp 			fi
   3124      0    stevel 		fi
   3125      0    stevel 
   3126   3252        dp 		sdiff_to_html $ofile $nfile $F $DIR "$COMM" \
   3127   3252        dp 		    > $WDIR/$DIR/$F.sdiff.html
   3128      0    stevel 		print " sdiffs\c"
   3129      0    stevel 
   3130   3252        dp 		print " frames\c"
   3131      0    stevel 
   3132      0    stevel 		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
   3133      0    stevel 
   3134   3252        dp 		difflines $ofile $nfile > $WDIR/$DIR/$F.count
   3135   3252        dp 
   3136   3252        dp 	elif [[ -f $ofile && -f $nfile && -n $mv_but_nodiff ]]; then
   3137   3252        dp 		# renamed file: may also have differences
   3138   3252        dp 		difflines $ofile $nfile > $WDIR/$DIR/$F.count
   3139   3252        dp 	elif [[ -f $nfile ]]; then
   3140      0    stevel 		# new file: count added lines
   3141   3252        dp 		difflines /dev/null $nfile > $WDIR/$DIR/$F.count
   3142   3252        dp 	elif [[ -f $ofile ]]; then
   3143      0    stevel 		# old file: count deleted lines
   3144   3252        dp 		difflines $ofile /dev/null > $WDIR/$DIR/$F.count
   3145      0    stevel 	fi
   3146      0    stevel 
   3147   3252        dp 	#
   3148   3252        dp 	# Now we generate the postscript for this file.  We generate diffs
   3149   3252        dp 	# only in the event that there is delta, or the file is new (it seems
   3150   3252        dp 	# tree-killing to print out the contents of deleted files).
   3151   3252        dp 	#
   3152   3252        dp 	if [[ -f $nfile ]]; then
   3153   3252        dp 		ocr=$ofile
   3154   3252        dp 		[[ ! -f $ofile ]] && ocr=/dev/null
   3155   3252        dp 
   3156   3252        dp 		if [[ -z $mv_but_nodiff ]]; then
   3157   3252        dp 			textcomm=`getcomments text $P $PP`
   3158   3295        dp 			if [[ -x $CODEREVIEW ]]; then
   3159   3295        dp 				$CODEREVIEW -y "$textcomm" \
   3160   3295        dp 				    -e $ocr $nfile \
   3161   3295        dp 				    > /tmp/$$.psfile 2>/dev/null &&
   3162   3295        dp 				    cat /tmp/$$.psfile >> $WDIR/$WNAME.ps
   3163   3295        dp 				if [[ $? -eq 0 ]]; then
   3164   3295        dp 					print " ps\c"
   3165   3295        dp 				else
   3166   3295        dp 					print " ps[fail]\c"
   3167   3295        dp 				fi
   3168   3252        dp 			fi
   3169   3252        dp 		fi
   3170   3252        dp 	fi
   3171   3252        dp 
   3172   7078  mjnelson 	if [[ -f $ofile ]]; then
   3173   7078  mjnelson 		source_to_html Old $PP < $ofile > $WDIR/$DIR/$F-.html
   3174      0    stevel 		print " old\c"
   3175      0    stevel 	fi
   3176      0    stevel 
   3177   3252        dp 	if [[ -f $nfile ]]; then
   3178   3252        dp 		source_to_html New $P < $nfile > $WDIR/$DIR/$F.html
   3179      0    stevel 		print " new\c"
   3180      0    stevel 	fi
   3181   7078  mjnelson 
   3182   7078  mjnelson 	cd $OWD
   3183      0    stevel 
   3184   3252        dp 	print
   3185      0    stevel done
   3186      0    stevel 
   3187   3252        dp frame_nav_js > $WDIR/ancnav.js
   3188   3252        dp frame_navigation > $WDIR/ancnav.html
   3189   3252        dp 
   3190   3295        dp if [[ ! -f $WDIR/$WNAME.ps ]]; then
   3191   3295        dp 	print " Generating PDF: Skipped: no output available"
   3192   3295        dp elif [[ -x $CODEREVIEW && -x $PS2PDF ]]; then
   3193   3295        dp 	print " Generating PDF: \c"
   3194   3295        dp 	fix_postscript $WDIR/$WNAME.ps | $PS2PDF - > $WDIR/$WNAME.pdf
   3195   3295        dp 	print "Done."
   3196   3295        dp else
   3197   3295        dp 	print " Generating PDF: Skipped: missing 'ps2pdf' or 'codereview'"
   3198   3295        dp fi
   3199      0    stevel 
   3200   5175      jmcp # If we're in OpenSolaris mode and there's a closed dir under $WDIR,
   3201   5175      jmcp # delete it - prevent accidental publishing of closed source
   3202   5175      jmcp 
   3203   5175      jmcp if [[ -n "$Oflag" ]]; then
   3204   8365  Vladimir 	$FIND $WDIR -type d -name closed -exec /bin/rm -rf {} \;
   3205   5175      jmcp fi
   3206   5175      jmcp 
   3207      0    stevel # Now build the index.html file that contains
   3208      0    stevel # links to the source files and their diffs.
   3209      0    stevel 
   3210      0    stevel cd $CWS
   3211      0    stevel 
   3212      0    stevel # Save total changed lines for Code Inspection.
   3213   3252        dp print "$TOTL" > $WDIR/TotalChangedLines
   3214      0    stevel 
   3215   3252        dp print "     index.html: \c"
   3216      0    stevel INDEXFILE=$WDIR/index.html
   3217      0    stevel exec 3<&1			# duplicate stdout to FD3.
   3218      0    stevel exec 1<&-			# Close stdout.
   3219      0    stevel exec > $INDEXFILE		# Open stdout to index file.
   3220      0    stevel 
   3221   3252        dp print "$HTML<head>$STDHEAD"
   3222   3252        dp print "<title>$WNAME</title>"
   3223   3252        dp print "</head>"
   3224   3252        dp print "<body id=\"SUNWwebrev\">"
   3225   3252        dp print "<div class=\"summary\">"
   3226   3252        dp print "<h2>Code Review for $WNAME</h2>"
   3227      0    stevel 
   3228   3252        dp print "<table>"
   3229      0    stevel 
   3230   3252        dp #
   3231   7078  mjnelson # Get the preparer's name:
   3232   3252        dp #
   3233   7078  mjnelson # If the SCM detected is Mercurial, and the configuration property
   3234   7078  mjnelson # ui.username is available, use that, but be careful to properly escape
   3235   7078  mjnelson # angle brackets (HTML syntax characters) in the email address.
   3236   7078  mjnelson #
   3237   7078  mjnelson # Otherwise, use the current userid in the form "John Doe (jdoe)", but
   3238   7078  mjnelson # to maintain compatibility with passwd(4), we must support '&' substitutions.
   3239   7078  mjnelson #
   3240   7078  mjnelson preparer=
   3241   7078  mjnelson if [[ "$SCM_MODE" == mercurial ]]; then
   3242   7078  mjnelson 	preparer=`hg showconfig ui.username 2>/dev/null`
   3243   7078  mjnelson 	if [[ -n "$preparer" ]]; then
   3244   7078  mjnelson 		preparer="$(echo "$preparer" | html_quote)"
   3245   7078  mjnelson 	fi
   3246   7078  mjnelson fi
   3247   7078  mjnelson if [[ -z "$preparer" ]]; then
   3248   7078  mjnelson 	preparer=$(
   3249   7078  mjnelson 	    $PERL -e '
   3250   7078  mjnelson 	        ($login, $pw, $uid, $gid, $quota, $cmt, $gcos) = getpwuid($<);
   3251   7078  mjnelson 	        if ($login) {
   3252   7078  mjnelson 	            $gcos =~ s/\&/ucfirst($login)/e;
   3253   7078  mjnelson 	            printf "%s (%s)\n", $gcos, $login;
   3254   7078  mjnelson 	        } else {
   3255   7078  mjnelson 	            printf "(unknown)\n";
   3256   7078  mjnelson 	        }
   3257   7078  mjnelson 	')
   3258   3252        dp fi
   3259   3252        dp 
   3260  10738     James PREPDATE=$(LC_ALL=C /usr/bin/date +%Y-%b-%d\ %R\ %z\ %Z)
   3261  10738     James print "<tr><th>Prepared by:</th><td>$preparer on $PREPDATE</td></tr>"
   3262   7078  mjnelson print "<tr><th>Workspace:</th><td>$CWS"
   3263   7078  mjnelson if [[ -n $CWS_REV ]]; then
   3264   7078  mjnelson 	print "(at $CWS_REV)"
   3265   7078  mjnelson fi
   3266   7078  mjnelson print "</td></tr>"
   3267   3252        dp print "<tr><th>Compare against:</th><td>"
   3268   3252        dp if [[ -n $parent_webrev ]]; then
   3269   3252        dp 	print "webrev at $parent_webrev"
   3270   3252        dp else
   3271   3252        dp 	print "$PWS"
   3272   7078  mjnelson 	if [[ -n $hg_parent_short ]]; then
   3273   7078  mjnelson 		print "(at $hg_parent_short)"
   3274   7078  mjnelson 	fi
   3275   3252        dp fi
   3276   3252        dp print "</td></tr>"
   3277   3252        dp print "<tr><th>Summary of changes:</th><td>"
   3278   3252        dp printCI $TOTL $TINS $TDEL $TMOD $TUNC
   3279   3252        dp print "</td></tr>"
   3280   3252        dp 
   3281   3252        dp if [[ -f $WDIR/$WNAME.patch ]]; then
   3282   9011   Lubomir 	wpatch_url="$(print $WNAME.patch | url_encode)"
   3283   3252        dp 	print "<tr><th>Patch of changes:</th><td>"
   3284   9011   Lubomir 	print "<a href=\"$wpatch_url\">$WNAME.patch</a></td></tr>"
   3285   3252        dp fi
   3286   3252        dp if [[ -f $WDIR/$WNAME.pdf ]]; then
   3287   9011   Lubomir 	wpdf_url="$(print $WNAME.pdf | url_encode)"
   3288   3252        dp 	print "<tr><th>Printable review:</th><td>"
   3289   9011   Lubomir 	print "<a href=\"$wpdf_url\">$WNAME.pdf</a></td></tr>"
   3290   3252        dp fi
   3291   3252        dp 
   3292   3252        dp if [[ -n "$iflag" ]]; then
   3293   3252        dp 	print "<tr><th>Author comments:</th><td><div>"
   3294   3252        dp 	cat /tmp/$$.include
   3295   3252        dp 	print "</div></td></tr>"
   3296   3252        dp fi
   3297   3252        dp print "</table>"
   3298   3252        dp print "</div>"
   3299   3252        dp 
   3300   3252        dp #
   3301   3252        dp # Second pass through the files: generate the rest of the index file
   3302   3252        dp #
   3303   3252        dp cat $FLIST | while read LINE
   3304      0    stevel do
   3305      0    stevel 	set - $LINE
   3306      0    stevel 	P=$1
   3307      0    stevel 
   3308   3252        dp 	if [[ $# == 2 ]]; then
   3309      0    stevel 		PP=$2
   3310   7078  mjnelson 		oldname="$PP"
   3311      0    stevel 	else
   3312      0    stevel 		PP=$P
   3313   3252        dp 		oldname=""
   3314   7078  mjnelson 	fi
   3315   7078  mjnelson 
   3316   7078  mjnelson 	mv_but_nodiff=
   3317   7078  mjnelson 	cmp $WDIR/raw_files/old/$PP $WDIR/raw_files/new/$P > /dev/null 2>&1
   3318   7078  mjnelson 	if [[ $? == 0 && -n "$oldname" ]]; then
   3319   7078  mjnelson 		mv_but_nodiff=1
   3320   3252        dp 	fi
   3321   3252        dp 
   3322   3252        dp 	DIR=${P%/*}
   3323   3252        dp 	if [[ $DIR == $P ]]; then
   3324   3252        dp 		DIR="."   # File at root of workspace
   3325      0    stevel 	fi
   3326      0    stevel 
   3327      0    stevel 	# Avoid processing the same file twice.
   3328      0    stevel 	# It's possible for renamed files to
   3329      0    stevel 	# appear twice in the file list
   3330      0    stevel 
   3331      0    stevel 	F=$WDIR/$P
   3332      0    stevel 
   3333   3252        dp 	print "<p>"
   3334      0    stevel 
   3335      0    stevel <