1#! /bin/sh
2# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3# Written by Mike Bianchi <MBianchi@Foveal.com <mailto:MBianchi@Foveal.com>>
4
5# This file is part of the gdiffmk utility, which is part of groff.
6
7# groff is free software; you can redistribute it and/or modify it
8# under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2, or (at your option)
10# any later version.
11
12# groff is distributed in the hope that it will be useful, but WITHOUT
13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15# License for more details.
16
17# You should have received a copy of the GNU General Public License
18# along with groff; see the files COPYING and LICENSE in the top
19# directory of the groff source.  If not, write to the Free Software
20# Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
21# This file is part of GNU gdiffmk.
22
23
24cmd=$( basename $0 )
25
26function Usage {
27	if test "$#" -gt 0
28	then
29		echo >&2 "${cmd}:  $@"
30	fi
31	echo >&2 "\
32
33Usage:  ${cmd} [ OPTIONS ] FILE1 FILE2 [ OUTPUT ]
34Place difference marks into the new version of a groff/nroff/troff document.
35FILE1 and FILE2 are compared, using \`diff', and FILE2 is output with
36groff \`.mc' requests added to indicate how it is different from FILE1.
37
38  FILE1   Previous version of the groff file.  \`-' means standard input.
39  FILE2   Current version of the groff file.   \`-' means standard input.
40          Either FILE1 or FILE2 can be standard input, but not both.
41  OUTPUT  Copy of FILE2 with \`.mc' commands added.
42          \`-' means standard output (the default).
43
44OPTIONS:
45  -a ADDMARK     Mark for added groff source lines.    Default: \`+'.
46  -c CHANGEMARK  Mark for changed groff source lines.  Default: \`|'.
47  -d DELETEMARK  Mark for deleted groff source lines.  Default: \`*'.
48
49  -D             Show the deleted portions from changed and deleted text.
50                  Default delimiting marks:  \`[[' .... \`]]'.
51  -B             By default, the deleted texts marked by the \`-D' option end
52                  with an added troff \`.br' command.  This option prevents
53                  the added \`.br'.
54  -M MARK1 MARK2 Change the delimiting marks for the \`-D' option.
55
56  -x DIFFCMD     Use a different diff(1) command;
57                  one that accepts the \`-Dname' option, such as GNU diff.
58  --version      Print version information on the standard output and exit.
59  --help         Print this message on the standard error.
60"
61	exit 255
62}
63
64
65function Exit {
66	exitcode=$1
67	shift
68	for arg
69	do
70		echo >&2 "${cmd}:  $1"
71		shift
72	done
73	exit ${exitcode}
74}
75
76#	Usage:  FileRead  exit_code  filename
77#
78#	Check for existence and readability of given file name.
79#	If not found or not readable, print message and exit with EXIT_CODE.
80function FileRead {
81	case "$2" in
82	-)
83		return
84		;;
85	esac
86
87	if test ! -e "$2"
88	then
89		Exit $1 "File \`$2' not found."
90	fi
91	if test ! -r "$2"
92	then
93		Exit $1 "File \`$2' not readable."
94	fi
95}
96
97
98#	Usage:  FileCreate  exit_code  filename
99#
100#	Create the given filename if it doesn't exist.
101#	If unable to create or write, print message and exit with EXIT_CODE.
102function FileCreate {
103	case "$2" in
104	-)
105		return
106		;;
107	esac
108
109	if ! touch "$2" 2>/dev/null
110	then
111		if test ! -e "$2"
112		then
113			Exit $1 "File \`$2' not created; " \
114			  "Cannot write directory \`$( dirname "$2" )'."
115		fi
116		Exit $1 "File \`$2' not writeable."
117	fi
118}
119
120function WouldClobber {
121	case "$2" in
122	-)
123		return
124		;;
125	esac
126
127	if test "$1" -ef "$3"
128	then
129		Exit 3 \
130		  "The $2 and OUTPUT arguments both point to the same file," \
131		  "\`$1', and it would be overwritten."
132	fi
133}
134
135ADDMARK='+'
136CHANGEMARK='|'
137DELETEMARK='*'
138MARK1='[['
139MARK2=']]'
140
141function RequiresArgument {
142	#	Process flags that take either concatenated or
143	#	separated values.
144	case "$1" in
145	-??*)
146		expr "$1" : '-.\(.*\)'
147		return 1
148		;;
149	esac
150
151	if test "$#" -lt 2
152	then
153		Exit 255 "Option \`$1' requires a value."
154	fi
155
156	echo "$2"
157	return 0
158}
159
160badoption=
161DIFFCMD=diff
162D_option=
163br=.br
164for OPTION
165do
166	case "${OPTION}" in
167	-a*)
168		ADDMARK=$( RequiresArgument "${OPTION}" $2 )		&&
169			shift
170		;;
171	-c*)
172		CHANGEMARK=$( RequiresArgument "${OPTION}" $2 )		&&
173			shift
174		;;
175	-d*)
176		DELETEMARK=$( RequiresArgument "${OPTION}" $2 )		&&
177			shift
178		;;
179	-D )
180		D_option=D_option
181		;;
182	-M* )
183		MARK1=$( RequiresArgument "${OPTION}" $2 )		&&
184			shift
185		if [ $# -lt 2 ]
186		then
187			Usage "Option \`-M' is missing the MARK2 value."
188		fi
189		MARK2=$2
190		shift
191		;;
192	-B )
193		br=.
194		;;
195	-x* )
196		DIFFCMD=$( RequiresArgument "${OPTION}" $2 )		&&
197			shift
198		;;
199	--version)
200		echo "GNU ${cmd} (groff) version @VERSION@"
201		exit 0
202		;;
203	--help)
204		Usage
205		;;
206	--)
207		#	What follows  --  are file arguments
208		shift
209		break
210		;;
211	-)
212		break
213		;;
214	-*)
215		badoption="${cmd}:  invalid option \`$1'"
216		;;
217	*)
218		break
219		;;
220	esac
221	shift
222done
223
224${DIFFCMD} -Dx /dev/null /dev/null >/dev/null 2>&1  ||
225	Usage "The \`${DIFFCMD}' program does not accept"	\
226		"the required \`-Dname' option.
227Use GNU diff instead.  See the \`-x DIFFCMD' option."
228
229if test -n "${badoption}"
230then
231	Usage "${badoption}"
232fi
233
234if test "$#" -lt 2  -o  "$#" -gt 3
235then
236	Usage "Incorrect number of arguments."
237fi
238
239if test "1$1" = 1-  -a  "2$2" = 2-
240then
241	Usage "Both FILE1 and FILE2 are \`-'."
242fi
243
244FILE1=$1
245FILE2=$2
246
247FileRead 1 "${FILE1}"
248FileRead 2 "${FILE2}"
249
250if test "$#" = 3
251then
252	case "$3" in
253	-)
254		#	output goes to standard output
255		;;
256	*)
257		#	output goes to a file
258		WouldClobber "${FILE1}" FILE1 "$3"
259		WouldClobber "${FILE2}" FILE2 "$3"
260
261		FileCreate 3 "$3"
262		exec >$3
263		;;
264	esac
265fi
266
267#	To make a very unlikely label even more unlikely ...
268label=__diffmk_$$__
269
270sed_script='
271		/^#ifdef '"${label}"'/,/^#endif \/\* '"${label}"'/ {
272		  /^#ifdef '"${label}"'/          s/.*/.mc '"${ADDMARK}"'/
273		  /^#endif \/\* '"${label}"'/     s/.*/.mc/
274		  p
275		  d
276		}
277		/^#ifndef '"${label}"'/,/^#endif \/\* [!not ]*'"${label}"'/ {
278		  /^#else \/\* '"${label}"'/,/^#endif \/\* '"${label}"'/ {
279		    /^#else \/\* '"${label}"'/    s/.*/.mc '"${CHANGEMARK}"'/
280		    /^#endif \/\* '"${label}"'/   s/.*/.mc/
281		    p
282		    d
283		  }
284		  /^#endif \/\* \(not\|!\) '"${label}"'/ {
285		   s/.*/.mc '"${DELETEMARK}"'/p
286		   a\
287.mc
288		  }
289		  d
290		}
291		p
292	'
293
294if [ ${D_option} ]
295then
296	sed_script='
297		/^#ifdef '"${label}"'/,/^#endif \/\* '"${label}"'/ {
298		  /^#ifdef '"${label}"'/          s/.*/.mc '"${ADDMARK}"'/
299		  /^#endif \/\* '"${label}"'/     s/.*/.mc/
300		  p
301		  d
302		}
303		/^#ifndef '"${label}"'/,/^#endif \/\* [!not ]*'"${label}"'/ {
304		  /^#ifndef '"${label}"'/ {
305		   i\
306'"${MARK1}"'
307		   d
308		  }
309		  /^#else \/\* '"${label}"'/ ! {
310		   /^#endif \/\* [!not ]*'"${label}"'/ ! {
311		    p
312		    d
313		   }
314		  }
315		  /^#else \/\* '"${label}"'/,/^#endif \/\* '"${label}"'/ {
316		    /^#else \/\* '"${label}"'/ {
317		     i\
318'"${MARK2}"'\
319'"${br}"'
320		     s/.*/.mc '"${CHANGEMARK}"'/
321		     a\
322.mc '"${CHANGEMARK}"'
323		     d
324		    }
325		    /^#endif \/\* '"${label}"'/   s/.*/.mc/
326		    p
327		    d
328		  }
329		  /^#endif \/\* \(not\|!\) '"${label}"'/ {
330		   i\
331'"${MARK2}"'\
332'"${br}"'
333		   s/.*/.mc '"${DELETEMARK}"'/p
334		   a\
335.mc
336		  }
337		  d
338		}
339		p
340	'
341fi
342
343diff -D"${label}" -- ${FILE1} ${FILE2}  |
344	sed -n "${sed_script}"
345
346# EOF
347