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