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