367 lines
6.7 KiB
Bash
367 lines
6.7 KiB
Bash
#!/bin/sh
|
|
# Copyright 2004-2015 Free Software Foundation, Inc.
|
|
# 2023-2024 G. Branden Robinson
|
|
#
|
|
# Written by Mike Bianchi <MBianchi@Foveal.com>
|
|
# Changes from May 2015 onward by the groff development team
|
|
#
|
|
# This file is part of gdiffmk.
|
|
#
|
|
# gdiffmk is distributed with groff, the GNU roff typesetting system.
|
|
#
|
|
# groff is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# groff is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
|
# License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Thanks to Peter Bray for debugging.
|
|
|
|
CMD=`basename $0`
|
|
|
|
Diagnose () {
|
|
echo >&2 "${CMD}: $@"
|
|
}
|
|
|
|
Usage () {
|
|
status=0
|
|
if test $# -gt 0
|
|
then
|
|
Diagnose "usage error: $@"
|
|
exec 2>&1
|
|
status=2
|
|
fi
|
|
cat >&2 <<EOF
|
|
usage: ${CMD} [-a add-mark] [-c change-mark] [-d delete-mark] \
|
|
[-x diff-command] [-D [-B] [-M mark1 mark2]] [--] file1 file2 \
|
|
[output-file]
|
|
usage: ${CMD} --version
|
|
usage: ${CMD} --help
|
|
EOF
|
|
if [ -n "$want_help" ]
|
|
then
|
|
cat >&2 <<EOF
|
|
|
|
Compare roff(7) documents file1 and file2, and write another, derived
|
|
from both, to the standard output stream (or output-file), adding margin
|
|
character ('mc') requests at places in the output where the input
|
|
documents differ.
|
|
EOF
|
|
fi
|
|
exit $status
|
|
}
|
|
|
|
|
|
Exit () {
|
|
exitcode=$1
|
|
shift
|
|
for arg
|
|
do
|
|
echo >&2 "${CMD}: $1"
|
|
shift
|
|
done
|
|
exit ${exitcode}
|
|
}
|
|
|
|
# Usage: FileRead exit_code filename
|
|
#
|
|
# Check for existence and readability of given file name.
|
|
# If not found or not readable, print message and exit with EXIT_CODE.
|
|
FileRead () {
|
|
case "$2" in
|
|
-)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
if test ! -f "$2"
|
|
then
|
|
Exit $1 "input file \"$2\" does not exist or is not a file"
|
|
fi
|
|
if test ! -r "$2"
|
|
then
|
|
Exit $1 "input file \"$2\" is not readable"
|
|
fi
|
|
}
|
|
|
|
|
|
# Usage: FileCreate exit_code filename
|
|
#
|
|
# Create the given filename if it doesn't exist.
|
|
# If unable to create or write, print message and exit with EXIT_CODE.
|
|
FileCreate () {
|
|
case "$2" in
|
|
-)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
touch "$2" 2>/dev/null
|
|
if test $? -ne 0
|
|
then
|
|
if test ! -f "$2"
|
|
then
|
|
Exit $1 "File '$2' not created; " \
|
|
"Cannot write directory '`dirname "$2"`'."
|
|
fi
|
|
Exit $1 "File '$2' not writeable."
|
|
fi
|
|
}
|
|
|
|
WouldClobber () {
|
|
case "$2" in
|
|
-)
|
|
return
|
|
;;
|
|
esac
|
|
|
|
cmd='test /dev/null -ef /dev/null > /dev/null 2>&1'
|
|
if ! /bin/sh -c "$cmd"
|
|
then
|
|
Exit 3 \
|
|
"The system's 'test' command does not support the" \
|
|
" '-ef' option; OUTPUT can be only the standard output."
|
|
else
|
|
if test "$1" -ef "$3"
|
|
then
|
|
Exit 4 \
|
|
"The $2 and OUTPUT arguments both point to the same file," \
|
|
"'$1', and it would be overwritten."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
ADDMARK='+'
|
|
CHANGEMARK='|'
|
|
DELETEMARK='*'
|
|
MARK1='[['
|
|
MARK2=']]'
|
|
|
|
# Given an option with an expected argument, echo the option argument.
|
|
# Return 0 if caller should further shift its argument list; 1 if not.
|
|
RequiresArgument () {
|
|
case "$1" in
|
|
-??*)
|
|
optarg=${1#-?}
|
|
option=${option%${optarg}}
|
|
|
|
if test -z "${optarg}"
|
|
then
|
|
Exit 2 "option '${option}' requires an argument"
|
|
fi
|
|
|
|
echo "${optarg}"
|
|
return 1
|
|
;;
|
|
*)
|
|
echo "$2"
|
|
return 0
|
|
;;
|
|
esac
|
|
}
|
|
|
|
BADOPTION=
|
|
DIFFCMD=diff
|
|
SEDCMD=sed
|
|
D_option=
|
|
br=.br
|
|
want_help=
|
|
while [ $# -gt 0 ]
|
|
do
|
|
OPTION="$1"
|
|
case "${OPTION}" in
|
|
-a*)
|
|
ADDMARK=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
;;
|
|
-c*)
|
|
CHANGEMARK=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
;;
|
|
-d*)
|
|
DELETEMARK=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
;;
|
|
-D )
|
|
D_option=D_option
|
|
;;
|
|
-M* )
|
|
MARK1=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
if [ $# -lt 2 ]
|
|
then
|
|
Usage "Option '-M' is missing the MARK2 value."
|
|
fi
|
|
MARK2="$2"
|
|
shift
|
|
;;
|
|
-B )
|
|
br=.
|
|
;;
|
|
-s* )
|
|
SEDCMD=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
;;
|
|
-x* )
|
|
DIFFCMD=`RequiresArgument "${OPTION}" "$2"` &&
|
|
shift
|
|
;;
|
|
--version)
|
|
echo "${CMD} (groff) version 1.24.1"
|
|
exit 0
|
|
;;
|
|
--help)
|
|
want_help=yes
|
|
Usage
|
|
;;
|
|
--)
|
|
# What follows -- are file arguments
|
|
shift
|
|
break
|
|
;;
|
|
-)
|
|
break
|
|
;;
|
|
-*)
|
|
BADOPTION="invalid option '$1'"
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if ! ${DIFFCMD} -Dx /dev/null /dev/null >/dev/null 2>&1
|
|
then
|
|
Exit 3 "The '${DIFFCMD}' program does not accept" \
|
|
"the required '-Dname' option.
|
|
Use GNU diff instead. See the '-x DIFFCMD' option. You can also
|
|
install GNU diff as 'gdiff' on your system."
|
|
fi
|
|
|
|
if test -n "${BADOPTION}"
|
|
then
|
|
Usage "${BADOPTION}"
|
|
fi
|
|
|
|
if test $# -lt 2 || test $# -gt 3
|
|
then
|
|
Usage "expected 2 or 3 operands, got $#"
|
|
fi
|
|
|
|
if test "1$1" = "1-" && test "2$2" = "2-"
|
|
then
|
|
Usage "attempting to compare standard input to itself"
|
|
fi
|
|
|
|
FILE1="$1"
|
|
FILE2="$2"
|
|
|
|
FileRead 1 "${FILE1}"
|
|
FileRead 2 "${FILE2}"
|
|
|
|
if test $# = 3
|
|
then
|
|
case "$3" in
|
|
-)
|
|
# output goes to standard output
|
|
;;
|
|
*)
|
|
# output goes to a file
|
|
WouldClobber "${FILE1}" FILE1 "$3"
|
|
WouldClobber "${FILE2}" FILE2 "$3"
|
|
|
|
FileCreate 3 "$3"
|
|
exec >$3
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# To make a very unlikely LABEL even more unlikely ...
|
|
LABEL=__diffmk_$$__
|
|
|
|
SED_SCRIPT='
|
|
/^#ifdef '"${LABEL}"'/,/^#endif \/\* '"${LABEL}"'/ {
|
|
/^#ifdef '"${LABEL}"'/ s/.*/.mc '"${ADDMARK}"'/
|
|
/^#endif \/\* '"${LABEL}"'/ s/.*/.mc/
|
|
p
|
|
d
|
|
}
|
|
/^#ifndef '"${LABEL}"'/,/^#endif \/\* [!not ]*'"${LABEL}"'/ {
|
|
/^#else \/\* '"${LABEL}"'/,/^#endif \/\* '"${LABEL}"'/ {
|
|
/^#else \/\* '"${LABEL}"'/ s/.*/.mc '"${CHANGEMARK}"'/
|
|
/^#endif \/\* '"${LABEL}"'/ s/.*/.mc/
|
|
p
|
|
d
|
|
}
|
|
/^#endif \/\* [!not ]*'"${LABEL}"'/ {
|
|
s/.*/.mc '"${DELETEMARK}"'/p
|
|
a\
|
|
.mc
|
|
}
|
|
d
|
|
}
|
|
p
|
|
'
|
|
|
|
if [ ${D_option} ]
|
|
then
|
|
SED_SCRIPT='
|
|
/^#ifdef '"${LABEL}"'/,/^#endif \/\* '"${LABEL}"'/ {
|
|
/^#ifdef '"${LABEL}"'/ s/.*/.mc '"${ADDMARK}"'/
|
|
/^#endif \/\* '"${LABEL}"'/ s/.*/.mc/
|
|
p
|
|
d
|
|
}
|
|
/^#ifndef '"${LABEL}"'/,/^#endif \/\* [!not ]*'"${LABEL}"'/ {
|
|
/^#ifndef '"${LABEL}"'/ {
|
|
i\
|
|
'"${MARK1}"'
|
|
d
|
|
}
|
|
/^#else \/\* '"${LABEL}"'/ !{
|
|
/^#endif \/\* [!not ]*'"${LABEL}"'/ !{
|
|
p
|
|
d
|
|
}
|
|
}
|
|
/^#else \/\* '"${LABEL}"'/,/^#endif \/\* '"${LABEL}"'/ {
|
|
/^#else \/\* '"${LABEL}"'/ {
|
|
i\
|
|
'"${MARK2}"'\
|
|
'"${br}"'
|
|
s/.*/.mc '"${CHANGEMARK}"'/
|
|
a\
|
|
.mc '"${CHANGEMARK}"'
|
|
d
|
|
}
|
|
/^#endif \/\* '"${LABEL}"'/ s/.*/.mc/
|
|
p
|
|
d
|
|
}
|
|
/^#endif \/\* [!not ]*'"${LABEL}"'/ {
|
|
i\
|
|
'"${MARK2}"'\
|
|
'"${br}"'
|
|
s/.*/.mc '"${DELETEMARK}"'/p
|
|
a\
|
|
.mc
|
|
}
|
|
d
|
|
}
|
|
p
|
|
'
|
|
fi
|
|
|
|
${DIFFCMD} -D"${LABEL}" -- "${FILE1}" "${FILE2}" |
|
|
${SEDCMD} -n "${SED_SCRIPT}"
|
|
|
|
# EOF
|