xref: /illumos-gate/usr/src/tools/scripts/webrev.sh (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1#!/usr/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License, Version 1.0 only
7# (the "License").  You may not use this file except in compliance
8# with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or http://www.opensolaris.org/os/licensing.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23#
24# ident	"%Z%%M%	%I%	%E% SMI"
25#
26# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
27# Use is subject to license terms.
28#
29# This script takes a file list and a workspace
30# and builds a set of html files suitable for doing
31# a code review of source changes via a web page.
32#
33# Here's how you use it:
34#
35#	$ webrev file.list
36#
37# Alternatively, just run "webrev -l" and it'll extract
38# a file list from the output of "putback -n" that will
39# include any files updated, created, or currently sccs
40# checked out. The script creates a "webrev" directory
41# in the workspace directory that contains all the generated
42# html files.  It also stashes a copy of the file list in
43# there.
44#
45#
46# 1) If you run "webrev -l" it'll extract a file list from
47#    the output of "putback -n" that will include any files
48#    updated, created, or currently checked out.  This is
49#    the easiest way to use webrev.  If you use the "-l"
50#    option to generate the file list then skip to step (4).
51#    Note: if the workspace is large (e.g. all of Solaris usr/src
52#    then this might take a while. You can run "webrev -l -f flp"
53#    to have webrev extract a file list from the output of
54#    "putback -n -f flp".
55#
56#    The file list created by "webrev -l" is stashed in the
57#    webrev directory as "file.list".
58#
59#    If you would like more control over the file list then
60#    create a file containing a list of all the files to
61#    be included in your review with paths relative to your
62#    workspace directory, e.g.
63#
64#          usr/src/uts/common/fs/nfs/nfs_subr.c
65#          usr/src/uts/common/fs/nfs/nfs_export.c
66#          usr/src/cmd/fs.d/nfs/mountd/mountd.c
67#           :
68#
69#    Include the paths of any files added, deleted, or modified.
70#    You can keep this list of files in the webrev directory
71#    that the script creates in your workspace directory
72#    (CODEMGR_WS).
73#
74# 2) The script needs to be able locate your workspace and
75#    its parent.  If you have already activated your workspace
76#    with the "ws" command then the script will use the
77#    CODEMGR_WS environment variable.  If you are not working
78#    within a workspace activation, then you'll need to set
79#    the environment variable within the file list, e.g.
80#
81#          CODEMGR_WS=/home/brent/myws
82#
83#          usr/src/uts/common/fs/nfs/nfs_subr.c
84#          usr/src/uts/common/fs/nfs/nfs_export.c
85#          usr/src/cmd/fs.d/nfs/mountd/mountd.c
86#           :
87#
88#    If you would like to compare against some other workspace
89#    that is not the parent, then you can set the CODEMGR_PARENT
90#    environment variable in the file list, e.g.
91#
92#          CODEMGR_WS=/home/brent/myws
93#          CODEMGR_PARENT=/ws/on297-gate
94#
95#          usr/src/uts/common/fs/nfs/nfs_subr.c
96#          usr/src/uts/common/fs/nfs/nfs_export.c
97#          usr/src/cmd/fs.d/nfs/mountd/mountd.c
98#           :
99#
100# 3) Run this script with the name of the file containing
101#    the file list as an argument, e.g.
102#
103#      $ webrev  file.list
104#
105#    If you supply "-" as the name of the file, then stdin
106#    will be used.
107#
108#    If you use the "-w" flag, i.e. "webrev  -w  file.list"
109#    then webrev will assume the file list is in the format
110#    expected by the "wx" package: pathname lines alternating
111#    with SCCS comment lines separated by blank lines, e.g.
112#
113#          usr/src/uts/common/fs/nfs/nfs_subr.c
114#
115#          1206578 Fix spelling error in comment
116#
117#          usr/src/uts/common/fs/nfs/nfs_export.c
118#
119#          4039272 cstyle fixes
120#
121#          usr/src/cmd/fs.d/nfs/mountd/mountd.c
122#
123#          1927634 mountd daemon doesn't handle expletives
124#
125#    Embedded bug ids (any sequence of 5 or more digits)
126#    will be converted to a URL (see URL environment variable
127#    below).
128#
129# 4) For each file in the list, the script will compare it
130#    with the version in the parent workspace (CODEMGR_PARENT)
131#    and generate context and side-by-side diffs (sdiffs) as
132#    HTML files as well as HTML renderings of the old and new
133#    files with prepended line numbers for easy cross-checking
134#    with diffs.
135#
136#    The HTML files will have additional formatting to
137#    color code the source lines:
138#
139#      unchanged : black
140#        removed : brown
141#        changed : blue
142#            new : bold blue
143#
144#
145# 5) Webrev will create a directory $CODEMGR_WS/webrev
146#    and create the HTML files in a hierarchy beneath
147#    this directory. Links to these HTML files will be
148#    built into an index.html file in the "webrev" directory.
149#    If you would like the "webrev" directory to appear
150#    somewhere other than $CODEMGR_WS, then set the WDIR
151#    environment variable, e.g.
152#
153#        WDIR=/tmp  webrev -l
154#
155#    Each file will be listed on a line with a link to
156#    its Cdiffs, Udiffs, Sdiffs, Old, and New versions.  A blank
157#    line will be inserted between filenames that do not exist
158#    within the same directory as a grouping aid.
159#    SCCS comments for each delta will be included
160#    automatically. Bug numbers (any sequence of 5 or more
161#    digits) in the comment will be replaced by a URL to
162#    your local bug server.  You may need to modify the URL
163#    below:
164#
165    if [[ -z $WEBREV_BUGURL ]]; then
166	URL='http://monaco.sfbay.sun.com/detail.jsp?cr='
167    else
168	URL="$WEBREV_BUGURL"
169    fi
170#
171#    Likewise, ARC cases will be replaced by a URL starting with:
172#
173     URL2="http://sac.eng.sun.com/"
174#
175#    As a review aid, you can add value to the index
176#    file by including text that explains the changes in front
177#    of the links for each file.  You might also add links
178#    to the one-pager, project plan, or other documents
179#    helpful to the reviewer.
180#
181# 6) View the index.html file with your web browser to
182#    verify that its what you want your reviewers to see.
183#    The browser must support HTML tables and colored fonts.
184#    Then send an Email invitation to your reviewers including
185#    the URL to the index.html file in your workspace.  If you
186#    use an "http:" URL then you can omit the "index.html"
187#    filename, e.g.
188#
189#          To: bob, jane, wendy
190#          Subject: Please review fix for bug 1234576
191#
192#          I'd be grateful if would review my bugfix.
193#          All the relevant information can be obtained
194#          with the following URL:
195#
196#             http://jurassic.eng/home/brent/myws/webrev
197#
198#          Thanks
199#                 Brent
200#
201###############
202#
203#    Acknowledgements to Rob Thurlow, Mike Eisler, Lin Ling,
204#    Rod Evans, Mike Kupfer, Greg Onufer, Glenn Skinner,
205#    Oleg Larin, David Robinson, Matthew Cross, David L. Paktor,
206#    Neal Gafter, John Beck, Darren Moffat, Norm Shulman, Bill Watson,
207#    Pedro Rubio and Bill Shannon for valuable feedback and insight in
208#    building this script.
209#
210#    Have fun!
211#			Brent Callaghan  11/28/96
212###############
213#
214#          Change Log
215#
216# 3/28/97  Add support for specifying stdin as a "-" argument.
217#
218# 6/15/97  Fix to allow file overwrite for users who set "noclobber"
219#
220# 8/19/97  Fix illegal "&" escape sequences (from Greg Onufer)
221#
222# 10/29/97 Create all HTML files under a "webrev" directory
223#          Add -bw flags to "sdiff"
224#
225# 3/9/98   Improvements to better handle Java code.
226#          Fix for quoting of code in <pre> blocks.
227#          Fix some color bugs.  SCCS fix with not
228#          getting appropriate parent version depending
229#          on whether child version is checked out or
230#          not (from Bill Shannon).
231#
232# 3/13/98  Added code from Bill Shannon's "spc" script
233#          To add SCCS comments automatically to index.html.
234#
235# 3/18/98  Added -l option to generate file list automatically.
236#
237# 4/4/98   Added -w option to support Bonwick's wx package
238#          active file list which can included pending
239#          SCCS comments.
240#          Reorganized layout of index file so that SCCS comments
241#          now come after the file diffs line.  This looks much
242#          better. Also, reduced the text point size in diffs
243#          so that more source code can be viewed.
244#
245# 3/6/98   Handle files in the root directory of the workspace.
246#
247# 10/15/98 Fix minor bugs in sdiff color coding.
248#          Replace long runs of unchanged lines in sdiff
249#          by a horiz rule.
250#	   Link bugids in SCCS & wx comments to web page via URL.
251#          Bracket HTML page with <html> ... </html>.
252#	   Add HTML comment to index file to help in placing
253#	   change comments.
254#
255# 10/22/98 Fixed a bug affecting wx comments output.
256#          File names in index file are now bold.
257#          Basename of child workspace is used as the title.
258#
259# 12/22/98 Allow user to specify WDIR target directory for
260#          "webrev" directory.
261#
262# 2/8/99   Allow file comparison with a parent that is not
263#          a workspace - just a raw directory hierarchy of
264#          files created by a workspace snapshot tool like
265#          freezept (from Matthew Cross).
266#
267# 3/18/99  Allow the -l option to extract values for
268#	   CODEMGR_WS and for CODEMGR_PARENT if they
269#          are not already defined.  Play the file list
270#          out through stdout once it's created
271#	   (from David L. Paktor).
272#
273# 3/18/99  Correctly handle the case where no changes are found
274#
275# 4/7/99   Handle case of relative name for -w filename.
276#
277# 8/20/99  Fix handling of file.list
278#
279# 10/25/99 Additions or deletions to the beginning of a file
280#          caused the lines to go out of synch.  Added new
281#          code to handle this case.  Thanks to Glenn Skinner
282#          for reporting the bug.
283#
284# 4/21/00  Added date of webrev run to last line of index page
285#	   (suggestion by David Robinson)
286#
287# 8/2/00   Changed "sort" to "sort -u" to eliminate
288#          duplicates in putback output. Thanks to
289#          Bill Shannon.
290#
291# 11/21/00 Added filenames to the HTML page titles.
292#          (suggestion by David Robinson)
293#
294# 11/21/00 Fixed a problem with lost sccs comments in a
295#          new file.  Also added a default for the -w wxfile
296#          flag.  Thanks to Darren Moffat for these.
297#
298# 11/22/00 Fix to detect and handle renames correctly.
299#
300# 1/17/01  Allow the use of a file list program (flp) to
301#          be specified as an argument to -l. For example:
302#          "webrev -l -f ~/aux.flp". An flp is a program
303#          that generates a file list. Thanks to Norm Shulman.
304#
305# 2/1/01   Invoke context diff from CDIFFCMD environment
306#          variable.  This allows an alternative diff
307#          command line to be invoked if set in the environment.
308#          Thanks to John Beck (a fan of udiff).
309#
310# 2/2/01   Change "sort -k1,1" to "sort -k 1,1"
311#          Bugfix from Neal Gafter
312#
313# 4/27/01  Added webrev script date to index page
314#	   Suggestion from John Beck
315#
316# 4/27/01  Protect HTML sensitive characters in SCCS
317#          delta comments. Bug reported by Pedro Rubio
318#
319# 7/24/01  Modify page title to be workspace name - suggestion
320#	   from Bill Watson.
321#
322# Following variable is set to SCCS delta date 20YY/MM/DD.
323# Note this will have to be changed in 2100 or when SCCS has support for
324# 4 digit years; whichever is the sooner!
325#
326  WEBREV_UPDATED=20%E%
327#
328###############
329
330REMOVED_COLOR=brown
331CHANGED_COLOR=blue
332NEW_COLOR=blue
333
334#
335# Make a piece of source code safe for display in an HTML <pre> block.
336#
337html_quote()
338{
339	sed -e "s/&/\&amp;/g" -e "s/</\&lt;/g" -e "s/>/\&gt;/g" "$@" | expand
340}
341
342sdiff_to_html()
343{
344#
345#  This function takes two files as arguments, obtains their diff,
346#  and processes the diff output to present the files as an HTML
347#  document with the files displayed side-by-side, differences
348#  shown in color.
349#
350#  This HTML generated by this function assumes that the browser
351#  can handle HTML 3.0 tables and colored text as implemented
352#  in Netscape 2.0.  The output is "wide" so it will be necessary
353#  to widen the browser window when viewing the output.
354#
355#  The function takes two files as arguments
356#  and the HTML will be delivered on stdout, e.g.
357#
358#    $ sdiff_html  prog.c-  prog.c  >  prog.diffs.html
359#
360#  In addition if WEBREV_FRAMES == 'yes' then framed_sdiff() is called
361#  which creates $2.frames.html in the webrev tree.
362#
363#  FYI: This function is rather unusual in its use of awk.
364#  The initial diff run produces conventional diff output
365#  showing changed lines mixed with editing codes.  The
366#  changes lines are ignored - we're interested in the
367#  editing codes, e.g.
368#
369#      8c8
370#      57a61
371#      63c66,76
372#      68,93d80
373#      106d90
374#      108,110d91
375#
376#  These editing codes are parsed by the awk script and used to
377#  generate another awk script that generates HTML, e.g the
378#  above lines would turn into something like this:
379#
380#      BEGIN { printf "<pre>\n" }
381#      function sp(n) {for (i=0;i<n;i++)printf "\n"}
382#      function wl(n) {printf "<FONT COLOR=%s>%3d %s </FONT>\n", n, NR, $0}
383#      NR==8           {wl("#7A7ADD");next}
384#      NR==54          {wl("#7A7ADD");sp(3);next}
385#      NR==56          {wl("#7A7ADD");next}
386#      NR==57          {wl("black");printf "\n"; next}
387#        :               :
388#
389#  This script is then run on the original source file to generate
390#  the HTML that corresponds to the source file.
391#
392#  The two HTML files are then combined into a single piece of
393#  HTML that uses an HTML table construct to present the files
394#  side by side.  You'll notice that the changes are color-coded:
395#
396#   black     - unchanged lines
397#   blue      - changed lines
398#   bold blue - new lines
399#   brown     - deleted lines
400#
401#  Blank lines are inserted in each file to keep unchanged
402#  lines in sync (side-by-side).  This format is familiar
403#  to users of sdiff(1) or Teamware's filemerge tool.
404
405diff -b $1 $2 > /tmp/$$.diffs
406
407#
408#  Now we have the diffs, generate the HTML for the old file.
409#
410
411TNAME=$2
412
413nawk '
414BEGIN	{
415	printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
416	printf "function wl(n) {printf \"<FONT COLOR=%%s>%%3d %%s </FONT>\\n\", n, NR, $0}\n"
417	printf "function bl() {printf \"%%3d %%s\\n\", NR, $0}\n"
418}
419/^</	{next}
420/^>/	{next}
421/^---/	{next}
422{
423	split($1, a, /[cad]/) ;
424	if (index($1, "a")) {
425		if (a[1] == 0) {
426			n = split(a[2], r, /,/);
427			if (n == 1)
428				printf "BEGIN\t\t{sp(1)}\n"
429			else
430				printf "BEGIN\t\t{sp(%d)}\n",\
431				(r[2] - r[1]) + 1
432			next
433		}
434
435		printf "NR==%s\t\t{", a[1]
436		n = split(a[2], r, /,/);
437		s = r[1];
438		if (n == 1)
439			printf "bl();printf \"\\n\"; next}\n"
440		else {
441			n = r[2] - r[1]
442			printf "bl();sp(%d);next}\n",\
443			(r[2] - r[1]) + 1
444		}
445		next
446	}
447	if (index($1, "d")) {
448		n = split(a[1], r, /,/);
449		n1 = r[1]
450		n2 = r[2]
451		if (n == 1)
452			printf "NR==%s\t\t{wl(\"'$REMOVED_COLOR'\") ; next}\n" , n1
453		else
454			printf "NR==%s,NR==%s\t{wl(\"'$REMOVED_COLOR'\") ; next}\n" , n1, n2
455		next
456	}
457	if (index($1, "c")) {
458		n = split(a[1], r, /,/);
459		n1 = r[1]
460		n2 = r[2]
461		final = n2
462		d1 = 0
463		if (n == 1)
464			printf "NR==%s\t\t{wl(\"'$CHANGED_COLOR'\");" , n1
465		else {
466			d1 = n2 - n1
467			printf "NR==%s,NR==%s\t{wl(\"'$CHANGED_COLOR'\");" , n1, n2
468		}
469		m = split(a[2], r, /,/);
470		n1 = r[1]
471		n2 = r[2]
472		if (m > 1) {
473			d2  = n2 - n1
474			if (d2 > d1) {
475				if (n > 1) printf "if (NR==%d)", final
476				printf "sp(%d);", d2 - d1
477			}
478		}
479		printf "next}\n" ;
480
481		next
482	}
483}
484END	{ printf "{printf \"%%3d %%s\\n\", NR, $0 }\n" }
485' /tmp/$$.diffs > /tmp/$$.file1
486
487html_quote $1 | nawk -f /tmp/$$.file1 > /tmp/$$.file1.html
488
489#
490#  Now generate the HTML for the new file
491#
492
493nawk '
494BEGIN	{
495	printf "function sp(n) {for (i=0;i<n;i++)printf \"\\n\"}\n"
496	printf "function wl(n) {printf \"<FONT COLOR=%%s>%%3d %%s </FONT>\\n\", n, NR, $0}\n"
497	printf "function wlb(n) {printf \"<FONT COLOR=%%s><b>%%3d %%s</b></FONT>\\n\", n, NR, $0}\n"
498	printf "function bl() {printf \"%%3d %%s\\n\", NR, $0}\n"
499}
500/^</	{next}
501/^>/	{next}
502/^---/	{next}
503{
504	split($1, a, /[cad]/) ;
505	if (index($1, "d")) {
506		if (a[2] == 0) {
507			n = split(a[1], r, /,/);
508			if (n == 1)
509				printf "BEGIN\t\t{sp(1)}\n"
510			else
511				printf "BEGIN\t\t{sp(%d)}\n",\
512				(r[2] - r[1]) + 1
513			next
514		}
515
516		printf "NR==%s\t\t{", a[2]
517		n = split(a[1], r, /,/);
518		s = r[1];
519		if (n == 1)
520			printf "bl();printf \"\\n\"; next}\n"
521		else {
522			n = r[2] - r[1]
523			printf "bl();sp(%d);next}\n",\
524			(r[2] - r[1]) + 1
525		}
526		next
527	}
528	if (index($1, "a")) {
529		n = split(a[2], r, /,/);
530		n1 = r[1]
531		n2 = r[2]
532		if (n == 1)
533			printf "NR==%s\t\t{wlb(\"'$NEW_COLOR'\") ; next}\n" , n1
534		else
535			printf "NR==%s,NR==%s\t{wlb(\"'$NEW_COLOR'\") ; next}\n" , n1, n2
536		next
537	}
538	if (index($1, "c")) {
539		n = split(a[2], r, /,/);
540		n1 = r[1]
541		n2 = r[2]
542		final = n2
543		d2 = 0;
544		if (n == 1) {
545			final = n1
546			printf "NR==%s\t\t{wl(\"'$CHANGED_COLOR'\");" , n1
547		} else {
548			d2 = n2 - n1
549			printf "NR==%s,NR==%s\t{wl(\"'$CHANGED_COLOR'\");" , n1, n2
550		}
551		m = split(a[1], r, /,/);
552		n1 = r[1]
553		n2 = r[2]
554		if (m > 1) {
555			d1  = n2 - n1
556			if (d1 > d2) {
557				if (n > 1) printf "if (NR==%d)", final
558				printf "sp(%d);", d1 - d2
559			}
560		}
561		printf "next}\n" ;
562		next
563	}
564}
565END	{ printf "{printf \"%%3d %%s\\n\", NR, $0 }\n" }
566' /tmp/$$.diffs > /tmp/$$.file2
567
568html_quote $2 | nawk -f /tmp/$$.file2 > /tmp/$$.file2.html
569
570# Now combine into a table
571
572echo "<body bgcolor=#EEEEEE>"
573echo "<title> Sdiff $TNAME </title>"
574echo "<table><tr valign=top>"
575echo "<td><pre>"
576
577strip_unchanged /tmp/$$.file1.html
578
579echo "</pre></td><td><pre>"
580
581strip_unchanged /tmp/$$.file2.html
582
583echo "</pre></td>"
584echo "</tr></table>"
585
586if [[ $WEBREV_FRAMES == 'yes' ]]; then
587    framed_sdiff $TNAME /tmp/$$.file1.html /tmp/$$.file2.html
588fi
589
590}
591
592####################################
593
594function framed_sdiff
595{
596# Expects html files created by sdiff_to_html which it then augments
597# with HTML navigation anchors.
598#
599# NOTE: We rely on standard usage of $TNAME and $WDIR/$DIR.
600#
601    typeset TNAME=$1
602    typeset file1=$2
603    typeset file2=$3
604    typeset RTOP
605    # Make the rhs/lhs files and output the frameset file.
606    insert_anchors $file1 > $WDIR/$DIR/$TNAME.lhs.html
607    insert_anchors $file2 > $WDIR/$DIR/$TNAME.rhs.html
608    # Enable html files to access WDIR via a relative path.
609    RTOP=$(relative_cws)
610    cat > $WDIR/$DIR/$TNAME.frames.html <<-EOF
611	<html><head>
612	    <title>Framed Sdiff for $TNAME</title>
613	  </head>
614	  <FRAMESET ROWS="*,50">
615	    <FRAMESET COLS="50%,50%">
616	      <FRAME SRC="$TNAME.lhs.html" SCROLLING="auto" NAME="lhs">
617	      <FRAME SRC="$TNAME.rhs.html" SCROLLING="auto" NAME="rhs">
618	    </FRAMESET>
619	  <FRAME SRC="${RTOP}ancnav.html" SCROLLING="no" MARGINWIDTH="0"
620	   MARGINHEIGHT="0">
621	  <NOFRAMES>
622	    <P>Alas FRAMES webrev requires that your browser supports FRAMES
623	    and has the feature enabled.  
624	    <a href="index.html">Return to webrev index</a>.</p>
625	  </NOFRAMES>
626	  </FRAMESET>
627	</html>
628	EOF
629}
630
631####################################
632
633strip_unchanged()
634{
635# Removes chunks of sdiff documents that have not
636# changed. This makes it easier for a code reviewer
637# to find the bits that have changed.
638#
639# Deleted lines of text are replaced by an
640# horizontal rule. Some identical lines are
641# retained before and after the changed lines
642# to provide some context.  The number of these
643# lines is controlled by the variable C in the
644# nawk script below.
645#
646# The script detects changed lines as any line
647# that has a "FONT COLOR=" string embedded (unchanged
648# lines use the default color and have no FONT directive).
649# Blank lines (without a sequence number) are also detected
650# since they flag lines that have been inserted or deleted.
651
652nawk '
653
654BEGIN	{ C = c = 20 }
655NF == 0 || /FONT COLOR=/ {
656	if (c > C) {
657		c -= C
658		inx = 0
659                if (c > C) {
660			print "\n<hr>"
661			inx = c % C
662			c = C
663		}
664
665		for (i = 0; i < c; i++)
666			print ln[(inx + i) % C]
667	}
668	c = 0;
669	print
670	next
671}
672{	if (c >= C) {
673		ln[c % C] = $0
674                c++;
675		next;
676	}
677	c++;
678	print
679}
680END	{ if (c > (C * 2)) print "\n<hr>" }
681
682' $1
683}
684####################################
685
686function insert_anchors
687{
688# Flag blocks of difference with sequentially numbered invisible
689# anchors.  These are used to drive the WEBREV_FRAMES version of the
690# sdiffs output.
691#
692# NOTE: Anchor zero flags the top of the file irrespective of changes,
693# an additional anchor is also appended to flag the bottom.
694#
695# The script detects changed lines as any line that has a "<FONT
696# COLOR=" string embedded (unchanged lines use the default color and
697# have no FONT directive).  Blank lines (without a sequence number)
698# are also detected since they flag lines that have been inserted or
699# deleted.
700#
701# In addition, here is a good place to top and tail the document for
702# use in its parent frame.  We add a lot of blank lines to tackily
703# assist the last anchors to have an effect on the screen.
704
705print '<html>\n<body bgcolor="#EEEEEE">\n<pre>'
706
707nawk '
708function ia() {
709	printf "<A NAME=\"%d\"></A>", anc++;
710}
711BEGIN {
712	anc=0;
713	inblock=1;
714	ia();
715}
716NF == 0 || /^<FONT COLOR=/ {
717	if (inblock == 0) {
718		ia();
719		inblock=1;
720	}
721	print;
722	next;
723}
724{
725	inblock=0;
726	print;
727}
728END {
729	ia();
730	print "<center><font color=\"red\"><b>--- EOF ---</b></font></center>";
731	for(i=0;i<8;i++) printf "\n\n\n\n\n\n\n\n\n\n";
732}
733' $1
734
735print '</pre>\n</html>'
736}
737
738####################################
739
740function relative_cws
741{
742#
743# Print a relative return path from PWD to CWS.  for example if
744# PWD=/ws/onnv-gate/usr/src/tools/scripts and CWS=/ws/onnv-gate this
745# function would print "../../../../".
746#
747# In the event that CWS is not in PWD a warning is printed to stderr,
748# WDIR is returned and thus the resulting webrev is not relocatable.
749#
750    typeset cur="${PWD##$CWS(/)}" ret
751    if [[ $PWD == $cur ]]; then # Should never happen.
752	print -u2 "\nWarning: relative_cws: \"$PWD\" not relative to \"$CWS\"."
753	print -u2 "Check input paths.  Framed webrev will not be relocatable!"
754	print $WDIR
755    else
756	while [[ -n ${cur} ]]
757	do
758	    cur=${cur%%*(/)*([!/])}
759	    ret="../$ret"
760	done
761	print $ret
762    fi
763}
764
765####################################
766
767function frame_navigation
768{
769# Output anchor navigation file for framed sdiffs.
770cat << \EOF
771<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
772<html><head><title>Anchor Navigation</title>
773<meta http-equiv="Content-Script-Type" content="text/javascript">
774<meta http-equiv="Content-Type" content="text/html">
775    <style>
776      div.button td { background: #900;}
777      div.button a { color: white }
778      div.button a:hover { background: black; color: white }
779    </style>
780    <script language="JavaScript">
781<!--
782var anc=0;
783var myInt;
784var scrolling=0;
785var sfactor;
786var scount=10;
787
788function scrollByPix() {
789	if (scount<=0) {
790		sfactor*=1.2;
791		scount=10;
792	}
793	parent.lhs.scrollBy(0,sfactor);
794	parent.rhs.scrollBy(0,sfactor);
795	scount--;
796}
797
798function scrollByAnc(num) {
799	if (num < 0) {
800		anc=0;
801		num=0;
802	}
803	if (num >= parent.lhs.document.anchors.length) {
804		anc=parent.lhs.document.anchors.length - 1;
805		num=anc;
806	}
807	parent.lhs.location.replace(parent.lhs.location.pathname + "#" + num);
808	parent.rhs.location.replace(parent.rhs.location.pathname + "#" + num);
809	anc=num;
810	if (num <= 0) {
811	    document.diff.sync.value="BOF";
812	} else if (num < parent.lhs.document.anchors.length - 1) {
813	    document.diff.sync.value=num;
814        } else {
815	    document.diff.sync.value="EOF";
816	}
817	// Scroll back a little to expose previous lines.
818	parent.lhs.scrollBy(0,-30);
819	parent.rhs.scrollBy(0,-30);
820}
821
822function stopScroll() {
823	if (scrolling==1) {
824		clearInterval(myInt);
825		scrolling=0;
826	}
827}
828
829function startScroll() {
830	stopScroll();
831	scrolling=1;
832	myInt=setInterval("scrollByPix()",10);
833}
834
835function handlePress(b) {
836	switch (b) {
837	    case 1 :
838		scrollByAnc(-1);
839		break;
840	    case 2 :
841		scrollByAnc(anc-1);
842		break;
843	    case 3 :
844		sfactor=-3;
845		startScroll();
846		break;
847	    case 4 :
848		sfactor=3;
849		startScroll();
850		break;
851	    case 5 :
852		scrollByAnc(anc+1);
853		break;
854	    case 6 :
855		scrollByAnc(parent.lhs.document.anchors.length);
856		break;
857	}
858}
859
860function handleRelease(b) {
861	stopScroll();
862}
863
864function ValidateDiffNum(){
865        i=Number(document.diff.sync.value);
866	if (isNaN(i)) {
867		document.diff.sync.value=anc;
868	} else {
869		scrollByAnc(i);
870	}
871	return false;
872}
873
874//-->
875    </script>
876  </head>
877  <body>
878    <noscript lang="javascript">
879      <center>
880	<p><big>Framed Navigation controls require Javascript</big><br>
881	Either this browser is incompatable or javascript is not enabled</p>
882      </center>
883    </noscript>
884    <table width="100%" border="0" align="center">
885	<tr><th valign="middle" width="25%"><i>Diff navigation:</i></th>
886	  <td align="centre" valign="top" width="50%">
887	    <div class="button">
888	      <table border="0" cellpadding="2" align="center"><tr>
889		    <td align="center" valign="left">
890		      <a onMouseDown="handlePress(1);return true;"
891			 onMouseUp="handleRelease(1);return true;"
892			 onMouseOut="handleRelease(1);return true;"
893			 onClick="return false;"
894			 title="Go to Beginning Of file">BOF</a></td>
895		    <td align="center" valign="middle">
896		      <a onMouseDown="handlePress(3);return true;"
897			 onMouseUp="handleRelease(3);return true;"
898			 onMouseOut="handleRelease(3);return true;"
899			 title="Scroll Up: Press and Hold to accelerate"
900			 onClick="return false;">Scroll frames Up</a></td>
901		    <td align="center" valign="right">
902		      <a onMouseDown="handlePress(2);return true;"
903			 onMouseUp="handleRelease(2);return true;"
904			 onMouseOut="handleRelease(2);return true;"
905			 title="Go to previous Diff"
906			 onClick="return false;">Prev Diff</a>
907		    </td></tr>
908		  <tr>
909		    <td align="center" valign="left">
910		      <a onMouseDown="handlePress(6);return true;"
911			 onMouseUp="handleRelease(6);return true;"
912			 onMouseOut="handleRelease(6);return true;"
913			 onClick="return false;"
914			 title="Go to End Of File">EOF</a></td>
915		    <td align="center" valign="middle">
916		      <a onMouseDown="handlePress(4);return true;"
917			 onMouseUp="handleRelease(4);return true;"
918			 onMouseOut="handleRelease(4);return true;"
919			 title="Scroll Down: Press and Hold to accelerate"
920			 onClick="return false;">Scroll frames Down</a></td>
921		    <td align="center" valign="right">
922		      <a onMouseDown="handlePress(5);return true;"
923			 onMouseUp="handleRelease(5);return true;"
924			 onMouseOut="handleRelease(5);return true;"
925			 title="Go to next Diff"
926			 onClick="return false;">Next Diff</a></td>
927		  </tr></table>
928	    </dev>
929	  </TD>
930	  <th valign="middle" width="25%">
931	    <form name="diff" onsubmit="return ValidateDiffNum();">
932		<input name="sync" value="BOF" size="8" type="text">
933	    </form>
934	  </th>
935	</TR>
936    </table>
937  </body>
938</html>
939EOF
940}
941
942####################################
943
944diff_to_html()
945{
946TNAME=$1
947DIFFTYPE=$2
948
949html_quote | nawk '
950BEGIN	{printf "<body bgcolor=\"#EEEEEE\"><title>'$DIFFTYPE'diff '$TNAME'</title><pre>\n"}
951/^-------/	{ printf "<center><h1>%s</h1></center>\n", $0; next }
952/^\*\*\*\*/	{ printf "<hr>\n"; next}
953/^\*\*\*/	{ printf "<FONT COLOR=\"red\" SIZE=+1><b>%s</b></FONT>\n", $0 ; next}
954/^---/		{ printf "<FONT COLOR=\"green\" SIZE=+1><b>%s</b></FONT>\n", $0 ; next}
955/^\+/	{printf "<FONT COLOR=\"'$NEW_COLOR'\"><b>%s</b></FONT>\n", $0; next}
956/^!/	{printf "<FONT COLOR=\"'$CHANGED_COLOR'\">%s</FONT>\n", $0; next}
957/^-/	{printf "<FONT COLOR=\"'$REMOVED_COLOR'\">%s</FONT>\n", $0; next}
958	{printf "<FONT COLOR=\"black\">%s</FONT>\n", $0; next}
959END	{printf "</pre></FONT></body>\n"}
960'
961}
962
963####################################
964
965source_to_html()
966{
967WHICH=$1
968TNAME=$2
969
970html_quote | nawk '
971BEGIN	{printf "<body bgcolor=\"#EEEEEE\"><title>'"$WHICH $TNAME"'</title><pre>\n"}
972	{line += 1 ; printf "%3d %s\n", line, $0 }
973'
974}
975
976####################################
977# Find the first delta in the child that's not in the parent.
978# Get the newest delta from the parent, get all deltas from the
979# child starting with that delta, and then get all info starting
980# with the second oldest delta in that list (the first delta
981# unique to the child).
982#
983# This code adapted from Bill Shannon's "spc" script
984
985deltacomments()
986{
987pfile=$PWS/$1
988cfile=$CWS/$2
989
990if [ -f $pfile ]; then
991	psid=$(sccs prs -d:I: $pfile 2>/dev/null)
992else
993	psid=1.1
994fi
995
996set -A sids $(sccs prs -l -r$psid -d:I: $cfile 2>/dev/null)
997N=${#sids[@]}
998
999if [[ $N -ge 2 ]]; then
1000	sid1=${sids[$((N-2))]}	# Gets 2nd to last sid
1001
1002	echo "<ul>"
1003	sccs prs -l -r$sid1 $cfile  2>/dev/null |
1004	html_quote |
1005	sed -e 's|[0-9]\{5,\}|<a href='$URL'&>&</a>|g' \
1006	    -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}/[0-9]\{3\}\)|<a href='$URL2'\1/\2>\1 \2</a>|g'|
1007	nawk '/^COMMENTS:/ {p=1; printf "<li>"; continue}
1008		NF == 0 { continue }
1009		/^D / {p=0}
1010		{if (p==0) continue; print $0 "<br>"}'
1011	echo "</ul>"
1012fi
1013}
1014
1015####################################
1016# Given the pathname of a file, find its location
1017# in a "wx" active file list and print the following
1018# sccs comment. Embedded bugids (sequence of 5 or
1019# more digits) are turned into URLs.
1020
1021wxcomments()
1022{
1023
1024	echo "<blockquote><pre>"
1025	nawk '
1026	$1 == "'$1'" {
1027		do getline ; while (NF > 0)
1028		getline
1029		while (NF > 0) { print ; getline }
1030		exit
1031	}' < $WXFILE | html_quote |
1032	sed -e 's|[0-9]\{5,\}|<a href='$URL'&>&</a>|g' \
1033	    -e 's|\([A-Z]\{1,2\}ARC\)[ /]\([0-9]\{4\}/[0-9]\{3\}\)|<a href='$URL2'\1/\2>\1 \2</a>|g'
1034	echo "</pre></blockquote>"
1035}
1036
1037#####################################
1038# Calculate number of changes.
1039#
1040
1041function difflines
1042{
1043    integer tot chg del ins unc err
1044    typeset filename
1045
1046    diff -e $1 $2 | eval $( nawk '
1047    ## Change range of lines: N,Nc
1048    /^[0-9]*,[0-9]*c$/ {
1049	n=split(substr($1,1,length($1)-1), counts, ",");
1050	if (n != 2) {
1051	    error=2
1052	    exit;
1053	}
1054	## 3,5c means lines 3 , 4 and 5 are changed, a total of 3 lines.
1055	## following would be 5 - 3 = 2! Hence +1 for correction.
1056	r=(counts[2]-counts[1])+1;
1057	## Now count replacement lines: each represents a change instead
1058	## of a delete, so increment c and decrement r.
1059	while (getline != /^\.$/) {
1060		c++;
1061		r--;
1062	}
1063	## If there were more replacement lines than original lines,
1064	## then r will be negative; in this case there are no deletions,
1065	## but there are r changes that should be counted as adds, and
1066	## since r is negative, subtract it from a and add it to c.
1067	if (r < 0) {
1068		a-=r;
1069		c+=r;
1070	}
1071	## If there were more original lines than replacement lines, then
1072	## r will be positive; in this case, increment d by that much.
1073	if (r > 0) {
1074		d+=r;
1075	}
1076	next;
1077    }
1078
1079    ## Change lines: Nc
1080    /^[0-9].*c$/ {
1081	## The first line is a replacement; any more are additions.
1082	if (getline != /^\.$/) {
1083		c++;
1084		while (getline != /^\.$/) a++;
1085	}
1086	next;
1087    }
1088
1089    ## Add lines: both Na and N,Na
1090    /^[0-9].*a$/ {
1091	while (getline != /^\.$/) a++;
1092	next;
1093    }
1094
1095    ## Delete range of lines: N,Nd
1096    /^[0-9]*,[0-9]*d$/ {
1097	n=split(substr($1,1,length($1)-1), counts, ",");
1098	if (n != 2) {
1099	    error=2
1100	    exit;
1101	}
1102	## 3,5d means lines 3 , 4 and 5 are deleted, a total of 3 lines.
1103	## following would be 5 - 3 = 2! Hence +1 for correction.
1104	r=(counts[2]-counts[1])+1;
1105	d+=r;
1106	next;
1107    }
1108
1109    ## Delete line: Nd
1110    ## For example 10d says line 10 is deleted.
1111    /^[0-9]*d$/ {d++; next}
1112
1113    ## Should not get here!
1114    {
1115	error=1;
1116	exit;
1117    }
1118
1119    ## Finish off - print results
1120    END{
1121	printf("tot=%d;chg=%d;del=%d;ins=%d;err=%d\n",
1122	    (c+d+a), c, d, a, error);
1123    }' )
1124
1125    # End of nawk, Check to see if any trouble occurred.
1126    if (( $? > 0 || err > 0 )); then
1127	print "Unexpected Error occurred reading \`diff -e $1 $2\`: \$?=$?, err=" $err
1128    else
1129	# Accumulate totals
1130	(( TOTL += tot ))
1131	(( TCHG += chg ))
1132    	(( TDEL += del ))
1133	(( TINS += ins ))
1134	# Calculate unchanged lines
1135	wc -l $1 | read unc filename
1136	if (( unc > 0 )); then
1137	    (( unc -= del + chg ))
1138	    (( TUNC += unc ))
1139	fi
1140	# print summary
1141	printCI $tot $ins $del $chg $unc
1142    fi
1143}
1144
1145#####################################
1146# Print out Code Inspection figures similar to sccs-prt(1) format.
1147#
1148function printCI
1149{
1150    integer tot=$1 ins=$2 del=$3 chg=$4 unc=$5
1151    typeset str
1152    if (( tot == 1 )); then
1153	str="line"
1154    else
1155	str="lines"
1156    fi
1157    printf "%d %s changed : %d/%d/%d/%d %s\n" \
1158	$tot $str $ins $del $chg $unc "(inserted/deleted/modified/unchanged)"
1159}
1160
1161#####################################
1162#
1163#   Start Here
1164#
1165#####################################
1166
1167trap "rm -f /tmp/$$.* ; exit" 0 1 2 3 15
1168
1169set +o noclobber
1170
1171WDIFF=${WDIFF:-/ws/onnv-gate/public/bin/wdiff}
1172
1173FLIST=$1
1174
1175# By default enable frame diff.
1176WEBREV_FRAMES=${WEBREV_FRAMES:-yes}
1177
1178# Declare global total counters.
1179integer TOTL TINS TDEL TCHG TUNC
1180
1181if [ "$FLIST" = "-" ]; then
1182	FLIST=/tmp/$$.flist
1183	cat > $FLIST
1184fi
1185
1186# If the -l flag is given instead of the name of
1187# a file list, then generate the file list by
1188# extracting file names from a putback -n.
1189# Some names may come from the "update/create"
1190# messages and others from the "currently checked out"
1191# warning. Renames are detected here too.
1192# Extract values for CODEMGR_WS and CODEMGR_PARENT
1193# from the output of the putback -n as well, but remove
1194# them if they are already defined.
1195
1196if [ "$FLIST" = "-l" ]; then
1197
1198	FLIST=/tmp/$$.filelist
1199	print "Generating file list ...\c"
1200
1201	putback -n $2 $3 2>&1 |
1202	awk '/^update:|^create:/{print $2}
1203		/^Parent workspace:/{printf("CODEMGR_PARENT=%s\n",$3)}   \
1204		/^Child workspace:/{printf("CODEMGR_WS=%s\n",$3)}   \
1205		/^The following files/{p=1 ; continue}
1206		/^rename/{old=$3}
1207		$1 == "to:"{print $2, old}
1208		/^"/ {continue}
1209		NF == 0 {p=0 ; continue}
1210		{if (p==1) print $1}' |
1211	sort -r -k 1,1 -u | sort > $FLIST
1212
1213	print " Done\n"
1214fi
1215
1216# If the -w flag is given then assume the file
1217# list is in Bonwick's "wx" command format, i.e.
1218# pathname lines alternating with SCCS comment
1219# lines with blank lines as separators.
1220# Use the SCCS comments later in building
1221# the index.html file.
1222
1223if [ "$FLIST" = "-w" ]; then
1224	shift
1225	WXFILE=$1
1226
1227	# If the wx file pathname is relative
1228	# then make it absolute because the
1229	# webrev does a "cd" later on.
1230	#
1231	# If no wx file pathname is given, then
1232	# it defaults to "wx/active" in the
1233	# workspace directory.
1234
1235	if [ -z "${WXFILE}" ]; then
1236		WXFILE=${CODEMGR_WS}/wx/active
1237	elif [ ${WXFILE%%/*} ]; then
1238		WXFILE=$PWD/$WXFILE
1239	fi
1240
1241	FLIST=/tmp/$$.filelist
1242	nawk '{ c = 1; print;
1243	  while (getline) {
1244		if (NF == 0) { c = -c; continue }
1245		if (c > 0) print
1246	  }
1247	}' $WXFILE > $FLIST
1248fi
1249
1250if [ ! -f $FLIST ]; then
1251	echo "$FLIST: no such file"
1252
1253	echo "Usage: webrev <file>"
1254	echo "       webrev -"
1255	echo "       webrev -w [<wx file>]"
1256	echo "       webrev -l [-f flp]"
1257	exit 1
1258fi
1259
1260
1261# Remove workspace variables from the flist
1262# file if they're already set in the environment.
1263# We want the environment variables to take
1264# precedence over any set in the file list.
1265
1266if [ "$CODEMGR_WS" != "" ]; then
1267	egrep -v '^CODEMGR_WS=' $FLIST > $FLIST.$$
1268	mv $FLIST.$$ $FLIST
1269fi
1270if [ "$CODEMGR_PARENT" != "" ]; then
1271	egrep -v '^CODEMGR_PARENT=' $FLIST > $FLIST.$$
1272	mv $FLIST.$$ $FLIST
1273fi
1274
1275
1276# Now do an "eval" to set env variables that
1277# are listed in the file list.
1278
1279eval `sed -e "s/#.*$//" $FLIST | grep = `
1280
1281
1282if [ "$CODEMGR_WS" = "" ]; then
1283	echo "CODEMGR_WS not set."
1284	echo "Activate a workspace or set in $FLIST"
1285	exit 1
1286fi
1287
1288if [ ! -d $CODEMGR_WS ]; then
1289	echo "$CODEMGR_WS: no such workspace"
1290	exit 1
1291fi
1292
1293# Observe true directory name of CODEMGR_WS, as used later in webrev title.
1294CODEMGR_WS=$(cd $CODEMGR_WS;print $PWD)
1295
1296if [ "$CODEMGR_PARENT" = "" ]; then
1297	CODEMGR_PARENT=`workspace parent`
1298fi
1299
1300if [ ! -d $CODEMGR_PARENT ]; then
1301	echo "$CODEMGR_PARENT: no such parent workspace"
1302	exit 1
1303fi
1304
1305echo
1306echo CODEMGR_WS=$CODEMGR_WS
1307echo CODEMGR_PARENT=$CODEMGR_PARENT
1308echo
1309
1310CWS=$CODEMGR_WS
1311PWS=$CODEMGR_PARENT
1312WDIR=${WDIR:-$CWS}/webrev
1313if [ ${WDIR%%/*} ]; then
1314	WDIR=$PWD/$WDIR
1315fi
1316if [ ! -d $WDIR ]; then
1317	mkdir $WDIR
1318fi
1319
1320# Save the file list in the webrev dir
1321
1322if [ ! $FLIST -ef $WDIR/file.list ]; then
1323	cp $FLIST $WDIR/file.list
1324fi
1325
1326# Remove comments, blank lines and env variables from the file list
1327
1328sed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST |
1329
1330# ... and read lines from the cleaned-up file list
1331
1332while read LINE
1333do
1334	set - $LINE
1335	P=$1
1336
1337	# Normally, each line in the file list is
1338	# just a pathname of a file that has
1339	# been modified or created in the child.
1340	# A file that is renamed in the child workspace
1341	# has two names on the line: new name followed
1342	# by the old name.
1343
1344	if [ $# = 2 ]; then
1345		PP=$2			# old filename
1346		OLDNAME=" (was $PP)"
1347        	PDIR=${PP%/*}
1348        	if [ "$PDIR" == "$PP" ]; then
1349			PDIR="."   # File at root of workspace
1350		fi
1351
1352		PF=${PP##*/}
1353
1354	        DIR=${P%/*}
1355	        if [ "$DIR" == "$P" ]; then
1356			DIR="."   # File at root of workspace
1357		fi
1358
1359		F=${P##*/}
1360        else
1361		OLDNAME=""
1362	        DIR=${P%/*}
1363	        if [ "$DIR" == "$P" ]; then
1364			DIR="."   # File at root of workspace
1365		fi
1366
1367		F=${P##*/}
1368
1369		PP=$P
1370		PDIR=$DIR
1371		PF=$F
1372	fi
1373
1374
1375
1376	if [ ! -d $CWS/$DIR ]; then
1377		echo "  $CWS/$DIR: no such directory"
1378		continue
1379	fi
1380
1381	print "  $P$OLDNAME\n\t\c"
1382
1383	# Make the webrev mirror directory if necessary
1384
1385	if [ ! -d $WDIR/$DIR ]; then
1386		mkdir -p $WDIR/$DIR
1387	fi
1388
1389	# cd to the directory so the names are short
1390
1391	cd $CWS/$DIR
1392
1393	# If the child's version doesn't exist then
1394	# get a readonly copy.
1395
1396	if [ ! -f $F -a -f SCCS/s.$F ]; then
1397		sccs get -s $F
1398	fi
1399
1400	# Get the parent's version of the file. First see
1401	# whether the child's version is checked out and
1402	# get the parent's version with keywords expanded
1403	# or unexpanded as appropriate.
1404
1405	if [ -f $PWS/$PDIR/SCCS/s.$PF -o -f $PWS/$PDIR/SCCS/p.$PF ]; then
1406		if [ -f SCCS/p.$F ]; then
1407			sccs get -s -p -k $PWS/$PDIR/$PF > $WDIR/$DIR/$F-
1408		else
1409			sccs get -s -p    $PWS/$PDIR/$PF > $WDIR/$DIR/$F-
1410		fi
1411        else
1412                if [ -f $PWS/$PDIR/$PF ]; then
1413                        # Parent is not a real workspace, but just a raw
1414                        # directory tree - use the file that's there as
1415                        # the old file.
1416
1417                        cp $PWS/$PDIR/$PF $WDIR/$DIR/$F-
1418                fi
1419	fi
1420
1421	if [ ! -f $F -a ! -f $WDIR/$DIR/$F- ]; then
1422		echo "*** Error: file not in parent or child"
1423		continue
1424	fi
1425
1426	# If we have old and new versions of the file
1427	# then run the appropriate diffs.
1428
1429	if [ -f $F -a -f $WDIR/$DIR/$F- ]; then
1430		${CDIFFCMD:-diff -b -C 5} $WDIR/$DIR/$F- $F > $WDIR/$DIR/$F.cdiff
1431		diff_to_html $F "C" < $WDIR/$DIR/$F.cdiff > $WDIR/$DIR/$F.cdiff.html
1432		print " cdiffs\c"
1433
1434		${UDIFFCMD:-diff -b -U 5} $WDIR/$DIR/$F- $F > $WDIR/$DIR/$F.udiff
1435		diff_to_html $F "U" < $WDIR/$DIR/$F.udiff > $WDIR/$DIR/$F.udiff.html
1436		print " udiffs\c"
1437
1438		if [[ -x $WDIFF ]]; then
1439			$WDIFF -t "Wdiff $DIR/$F" $WDIR/$DIR/$F- $F > $WDIR/$DIR/$F.wdiff.html
1440			print " wdiffs\c"
1441		fi
1442
1443		sdiff_to_html $WDIR/$DIR/$F- $F > $WDIR/$DIR/$F.sdiff.html
1444		print " sdiffs\c"
1445
1446		if [[ $WEBREV_FRAMES == 'yes' ]]; then
1447			print " frames\c"
1448		fi
1449
1450		rm -f $WDIR/$DIR/$F.cdiff $WDIR/$DIR/$F.udiff
1451
1452		difflines $WDIR/$DIR/$F- $F > $WDIR/$DIR/$F.count
1453	elif [ -f $F ]; then
1454		# new file: count added lines
1455		difflines /dev/null $F > $WDIR/$DIR/$F.count
1456	elif [ -f $WDIR/$DIR/$F- ]; then
1457		# old file: count deleted lines
1458		difflines $WDIR/$DIR/$F- /dev/null > $WDIR/$DIR/$F.count
1459	fi
1460
1461	if [ -f $WDIR/$DIR/$F- ]; then
1462		source_to_html Old $PF < $WDIR/$DIR/$F- > $WDIR/$DIR/$F-.html
1463		rm -f $WDIR/$DIR/$F-
1464		print " old\c"
1465	fi
1466
1467	if [ -f $F ]; then
1468		source_to_html New $F < $F > $WDIR/$DIR/$F.html
1469		print " new\c"
1470	fi
1471
1472	echo
1473done
1474
1475if [[ $WEBREV_FRAMES == 'yes' ]]; then
1476	frame_navigation > $WDIR/ancnav.html
1477fi
1478
1479# Now build the index.html file that contains
1480# links to the source files and their diffs.
1481
1482cd $CWS
1483
1484# Save total changed lines for Code Inspection.
1485echo "$TOTL" > $WDIR/TotalChangedLines
1486
1487INDEXFILE=$WDIR/index.html
1488exec 3<&1			# duplicate stdout to FD3.
1489exec 1<&-			# Close stdout.
1490exec > $INDEXFILE		# Open stdout to index file.
1491
1492echo "<html>"
1493echo '<body bgcolor="#EEEEEE">'
1494echo "<title>${CWS##*/}</title>"
1495echo "<center><h1>${CWS##*/}</h1></center>"
1496echo "<p>"
1497echo "Parent workspace is $PWS <br>"
1498echo "Child  workspace is $CWS <br>"
1499printCI $TOTL $TINS $TDEL $TCHG $TUNC
1500echo "<hr>"
1501echo "<code>"
1502
1503sed -e "s/#.*$//" -e "/=/d" -e "/^[   ]*$/d" $FLIST |
1504
1505# ... and read lines from the cleaned-up file list
1506
1507while read LINE
1508do
1509	set - $LINE
1510	P=$1
1511
1512	if [ $# = 2 ]; then
1513		PP=$2
1514		OLDNAME=" <i>(was $PP)</i>"
1515	else
1516		PP=$P
1517		OLDNAME=""
1518	fi
1519
1520	# Avoid processing the same file twice.
1521	# It's possible for renamed files to
1522	# appear twice in the file list
1523
1524	F=$WDIR/$P
1525
1526	# Group files in
1527	# the same directory
1528
1529	D=${F%/*}
1530	if [ "$D" != "$PD" ]; then
1531		echo "<p>"
1532	else
1533		echo "<br>"
1534	fi
1535	echo
1536	echo
1537	PD=$D
1538
1539	# If there's a diffs file, make diffs links
1540
1541	if [ -f $F.cdiff.html ]; then
1542		echo "<a href=$P.cdiff.html>Cdiffs</a>"
1543		echo "<a href=$P.udiff.html>Udiffs</a>"
1544
1545		if [ -x $WDIFF ]; then
1546			echo "<a href=$P.wdiff.html>Wdiffs</a>"
1547		fi
1548
1549		echo "<a href=$P.sdiff.html>Sdiffs</a>"
1550
1551		if [[ $WEBREV_FRAMES == 'yes' ]]; then
1552			print "<a href=\"$P.frames.html\">Frames</a>"
1553		fi
1554	else
1555		echo "------ ------ ------"
1556
1557		if [ -x $WDIFF ]; then
1558			echo " ------"
1559		fi
1560
1561		if [[ $WEBREV_FRAMES == 'yes' ]]; then
1562			print " ------"
1563		fi
1564	fi
1565
1566	# If there's an old file, make the link
1567
1568	if [ -f $F-.html ]; then
1569		echo "<a href=$P-.html>Old</a>"
1570	else
1571		echo "---"
1572	fi
1573
1574	# If there's an new file, make the link
1575
1576	if [ -f $F.html ]; then
1577		echo "<a href=$P.html>New</a>"
1578	else
1579		echo "---"
1580	fi
1581	echo "<b>$P</b>$OLDNAME<p>"
1582
1583	# Insert delta comments
1584
1585	if [ "$WXFILE" ]; then
1586		wxcomments $P
1587	else
1588		deltacomments $PP $P
1589	fi
1590
1591	# Add additional comments comment
1592
1593	echo "<!-- Add comments to explain changes in $P here -->"
1594
1595	# Add count of changes.
1596
1597	if [ -f $F.count ]; then
1598	    echo "<blockquote>"
1599	    cat $F.count
1600	    echo "</blockquote>"
1601	    rm $F.count
1602	fi
1603done
1604
1605echo "</code>"
1606echo
1607echo
1608echo "<P><HR><FONT SIZE=2>"
1609echo "This code review page prepared with <b>webrev</b> (vers $WEBREV_UPDATED) on `date`."
1610echo "</FONT>"
1611echo "</html>"
1612
1613exec 1<&-			# Close FD 1.
1614exec 1<&3			# dup FD 3 to restore stdout.
1615exec 3<&-			# close FD 3.
1616
1617print "\n$WDIR created."
1618