[comp.os.minix] Patch for Minix, Part 1 of 3

frank@morgan.com (Frank Wortner) (05/28/88)

Here is a version of Larry Wall's patch program.  I've made a few
minor changes to get it to run under Minix.  The program has served me
well over the past month or two and I'm reasonably confident that it
works.

Have fun!

					Frank
					frank@morgan.com
					...!{uunet, sun}!mstan!frank
----------------------------------cut here----------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Configure
#	EXTERN.h
#	INTERN.h
#	Makefile
#	Makefile.SH
#	READ-ME-FIRST
#	README
#	common.h
#	config.h
#	inp.c
#	inp.h
#	patch.doc
# This archive created: Fri May 27 10:02:15 1988
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Configure'" '(21237 characters)'
if test -f 'Configure'
then
	echo shar: will not over-write existing file "'Configure'"
else
cat << \SHAR_EOF > 'Configure'
#! /bin/sh
#
# If these # comments don't work, trim them.  Don't worry about any other
# shell scripts, Configure will trim # comments from them for you.
#
# Note: if you are running ksh, be sure to say "sh Configure".
#
# (If you are trying to port this package to a machine without sh, I would
# suggest you cut out the prototypical config.h from the end of Configure
# and edit it to reflect your system.  Some packages may include samples
# of config.h for certain machines, so you might look for one of those.)
#
# $Header: Configure,v 2.0 86/09/17 15:32:58 lwall Exp $
#
# $Log:	Configure,v $
# Revision 2.0  86/09/17  15:32:58  lwall
# Baseline for netwide release.
# 
#
# Yes, you may rip this off to use in other distribution packages.
#
# (Note: this Configure script was generated automatically.  Rather than
# working with this copy of Configure, you may wish to get metaconfig.)

define='define'
undef='/*undef'

d_eunice=''
eunicefix=''
loclist=''
expr=''
sed=''
echo=''
cat=''
rm=''
mv=''
cp=''
tail=''
tr=''
mkdir=''
sort=''
uniq=''
grep=''
trylist=''
test=''
inews=''
egrep=''
more=''
pg=''
Mcc=''
vi=''
mailx=''
Log=''
Header=''
bin=''
cc=''
contains=''
cpp=''
d_index=''
d_void=''
iandd=''
libc=''
mansrc=''
manext=''
n=''
c=''
package=''
registers=''
reg1=''
reg2=''
reg3=''
reg4=''
reg5=''
reg6=''
reg7=''
reg8=''
reg9=''
reg10=''
reg11=''
reg12=''
reg13=''
reg14=''
reg15=''
reg16=''
spitshell=''
shsharp=''
sharpbang=''
startsh=''
CONFIG=''

package=patch

echo "Beginning of configuration questions for $package kit."
: Eunice requires " " instead of "", can you believe it
echo " "

: sanity checks
PATH='.:/bin:/usr/bin:/usr/local/bin:/usr/ucb:/usr/local:/usr/lbin:/etc'
export PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh $0; kill $$)

if test ! -t 0; then
    echo "Say 'sh Configure', not 'sh <Configure'"
    exit 1
fi

: some greps do not return status, grrr.
echo "grimblepritz" >grimble
if grep blurfldyick grimble >/dev/null 2>&1 ; then
    contains=contains
else
    if grep grimblepritz grimble >/dev/null 2>&1 ; then
	contains=grep
    else
	contains=contains
    fi
fi
rm -f grimble
: the following should work in any shell
case "$contains" in
contains*)
    echo " "
    echo "AGH!  Grep doesn't return a status.  Attempting remedial action."
    cat >contains <<'EOSS'
grep "$1" "$2" >.greptmp && cat .greptmp && test -s .greptmp
EOSS
chmod 755 contains
esac

: first determine how to suppress newline on echo command
echo "Checking echo to see how to suppress newlines..."
(echo "hi there\c" ; echo " ") >.echotmp
if $contains c .echotmp >/dev/null 2>&1 ; then
    echo "...using -n."
    n='-n'
    c=''
else
    echo "...using \\\c"
    echo "c."
    n=''
    c='\c'
fi
echo $n "Type carriage return to continue.  Your cursor should be here-->$c"
read ans
rm -f .echotmp

: now set up to do reads with possible shell escape
: if this does not work on your machine, 1,$ s/. myread/read ans/
cat <<EOSC >myread
ans='!'
while expr "X\$ans" : "X!" >/dev/null; do
    read ans
    case "\$ans" in
    !)
	sh
	echo " "
	echo $n "\$rp $c"
	;;
    !*)
	set \`expr "X\$ans" : "X!\(.*\)\$"\`
	sh -c "\$*"
	echo " "
	echo $n "\$rp $c"
	;;
    esac
done
rp='Your answer:'
EOSC

: general instructions
cat <<EOH
 
This installation shell script will examine your system and ask you questions
to determine how $package and any auxiliary files should be installed.  If you
get stuck on a question, you may use a ! shell escape to start a subshell or
execute a command.  Many of the questions will have default answers in
square brackets--typing carriage return will give you the default.

On some of the questions which ask for file or directory names you are
allowed to use the ~name construct to specify the login directory belonging
to "name", even if you don't have a shell which knows about that.  Questions
where this is allowed will be marked "(~name ok)".
EOH
rp="[Type carriage return to continue]"
echo $n "$rp $c"
read ans
cat <<EOH
Much effort has been expended to ensure that this shell script will run
on any Unix system.  If despite that it blows up on you, your best bet is
to edit Configure and run it again.  (Trying to install this package
without having run Configure may be well nigh impossible.)  Also, let me
(lwall@sdcrdcf.UUCP) know how I blew it.

This installation script affects things in two ways: 1) it may do direct
variable substitutions on some of the files included in this kit, and
2) it builds a config.h file for inclusion in C programs.  You may edit
any of these files as the need arises after running this script.

EOH
rp="[Type carriage return to continue]"
echo $n "$rp $c"
read ans

: get old answers, if there is a config file out there
if test -f config.sh; then
    echo " "
    rp="I see a config.sh file.  Did Configure make it on THIS system? [y]"
    echo $n "$rp $c"
    read ans
    case "$ans" in
    n*) echo "OK, I'll ignore it.";;
    *)  echo "Fetching default answers from your old config.sh file..."
        . config.sh
	;;
    esac
fi

: get list of predefined functions in a handy place
echo " "
if test -f /lib/libc.a; then
    echo "Your C library is in /lib/libc.a.  You're normal."
    libc=/lib/libc.a
else
    if test -f /usr/lib/libc.a; then
	echo "Your C library is in /usr/lib/libc.a, of all places."
	libc=/usr/lib/libc.a
    else
	if test -f "$libc"; then
	    echo "Your C library is in $libc, like you said before."
	else
	    cat <<'EOM'
 
I can't seem to find your C library.  I've looked for /lib/libc.a and
/usr/lib/libc.a, but neither of those are there.  What is the full name
EOM
	    echo $n "of your C library? $c"
	    rp='C library full name?'
	    read ans
	    libc="$ans"
	fi
    fi
fi
echo " "
echo $n "Extracting names from $libc for later perusal...$c"
if ar t $libc > libc.list; then
    echo "done"
else
    echo " "
    echo "The archiver doesn't think $libc is a reasonable library."
    exit 1
fi

: make some quick guesses about what we are up against
echo " "
echo $n "Hmm...  $c"
if $contains SIGTSTP /usr/include/signal.h >/dev/null 2>&1 ; then
    echo "Looks kind of like a BSD system, but we'll see..."
    echo exit 0 >bsd
    echo exit 1 >usg
    echo exit 1 >v7
else
    if $contains fcntl libc.list >/dev/null 2>&1 ; then
	echo "Looks kind of like a USG system, but we'll see..."
	echo exit 1 >bsd
	echo exit 0 >usg
	echo exit 1 >v7
    else
	echo "Looks kind of like a version 7 system, but we'll see..."
	echo exit 1 >bsd
	echo exit 1 >usg
	echo exit 0 >v7
    fi
fi
if $contains vmssystem libc.list >/dev/null 2>&1 ; then
    cat <<'EOI'
There is, however, a strange, musty smell in the air that reminds me of
something...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit.
EOI
    echo "exit 0" >eunice
    eunicefix=unixtovms
    d_eunice="$define"
: it so happens the Eunice I know will not run shell scripts in Unix format
else
    echo " "
    echo "Congratulations.  You aren't running Eunice."
    eunicefix=':'
    d_eunice="$undef"
    echo "exit 1" >eunice
fi
chmod 755 bsd usg v7 eunice
$eunicefix bsd usg v7 eunice

: see if sh knows # comments
echo " "
echo "Checking your sh to see if it knows about # comments..."
if sh -c '#' >/dev/null 2>&1 ; then
    echo "Your sh handles # comments correctly."
    shsharp=true
    spitshell=cat
    echo " "
    echo "Okay, let's see if #! works on this system..."
    echo "#!/bin/echo hi" > try
    $eunicefix try
    chmod 755 try
    try > today
    if test -s today; then
	echo "It does."
	sharpbang='#!'
    else
	echo "#! /bin/echo hi" > try
	$eunicefix try
	chmod 755 try
	try > today
	if test -s today; then
	    echo "It does."
	    sharpbang='#! '
	else
	    echo "It doesn't."
	    sharpbang=': use '
	fi
    fi
else
    echo "Your sh doesn't grok # comments--I will strip them later on."
    shsharp=false
    echo "exec grep -v '^#'" >spitshell
    chmod 755 spitshell
    $eunicefix spitshell
    spitshell=`pwd`/spitshell
    echo "I presume that if # doesn't work, #! won't work either!"
    sharpbang=': use '
fi

: figure out how to guarantee sh startup
echo " "
echo "Checking out how to guarantee sh startup..."
startsh=$sharpbang'/bin/sh'
echo "Let's see if '$startsh' works..."
cat >try <<EOSS
$startsh
set abc
test "$?abc" != 1
EOSS

chmod 755 try
$eunicefix try
if try; then
    echo "Yup, it does."
else
    echo "Nope.  You may have to fix up the shell scripts to make sure sh runs them."
fi
rm -f try today

: find out where common programs are
echo " "
echo "Locating common programs..."
pth="/usr/ucb /bin /usr/bin /usr/local /usr/local/bin /usr/lbin /etc /usr/lib"
cat <<EOSC >loc
$startsh
thing=\$1
shift
dflt=\$1
shift
for dir in \$*; do
    case "\$thing" in
    .)
	if test -d \$dir/\$thing; then
	    echo \$dir
	    exit 0
	fi
	;;
    *)
	if test -f \$dir/\$thing; then
	    echo \$dir/\$thing
	    exit 0
	fi
	;;
    esac
done
echo \$dflt
exit 1
EOSC
chmod 755 loc
$eunicefix loc
loclist="
expr
sed
echo
cat
rm
grep
"
trylist="
test
Mcc
"
for file in $loclist; do
    xxx=`loc $file $file $pth`
    eval $file=$xxx
    case "$xxx" in
    /*)
	echo $file is in $xxx.
	;;
    *)
	echo "I don't know where $file is.  I hope it's in everyone's PATH."
	;;
    esac
done
echo " "
echo "Don't worry if any of the following aren't found..."
ans=offhand
for file in $trylist; do
    xxx=`loc $file $file $pth`
    eval $file=$xxx
    case "$xxx" in
    /*)
	echo $file is in $xxx.
	;;
    *)
	echo "I don't see $file out there, $ans."
	ans=either
	;;
    esac
done
case "$egrep" in
egrep)
    echo "Substituting grep for egrep."
    egrep=$grep
    ;;
esac
case "$test" in
test)
    echo "Hopefully test is built into your sh."
    ;;
/bin/test)
    echo " "
    echo $n 'Is your "test" built into sh? [n] (OK to guess) '"$c"
    rp='test built into sh? [n]'
    read ans
    case "$ans" in
    y*) test=test ;;
    esac
    ;;
*)
    test=test
    ;;
esac
case "$echo" in
echo)
    echo "Hopefully echo is built into your sh."
    ;;
/bin/echo)
    echo " "
    echo "Checking compatibility between /bin/echo and builtin echo (if any)..."
    $echo $n "hi there$c" >foo1
    echo $n "hi there$c" >foo2
    if cmp foo1 foo2 >/dev/null 2>&1; then
	echo "They are compatible.  In fact, they may be identical."
    else
	echo "They are not compatible--the echo builtin will be used."
	echo=echo
    fi
    $rm -f foo1 foo2
    ;;
*)
    echo=echo
    ;;
esac

: index or strcpy
$echo " "
if $contains index libc.list >/dev/null 2>&1 ; then
    $echo "Your system appears to use index() and rindex() rather than strchr()"
    $echo $n "and strrchr().  Is this correct? [y] $c"
    rp='index() rather than strchr()? [y]'
    read ans
    case "$ans" in
	n*|f*) d_index="$define" ;;
	*)     d_index="$undef" ;;
    esac
else
    $echo "Your system appears to use strchr() and strrchr() rather than index()"
    $echo $n "and rindex().  Is this correct? [y] $c"
    rp='strchr() rather than index()? [y]'
    read ans
    case "$ans" in
	n*|f*) d_index="$undef" ;;
	*)     d_index="$define" ;;
    esac
fi

: check for void type
$echo " "
$echo "Checking to see if your C compiler groks the void type..."
$cat >try.c <<'EOCP'
void main();
EOCP
if cc -c try.c >/dev/null 2>&1 ; then
    d_void="$undef"
    $echo "Yup, it does."
else
    d_void="$define"
    $echo "Nope, it doesn't (boo hiss).  I will substitute int."
fi
$rm -f try.*

: see how we invoke the C preprocessor
echo " "
echo "Checking to see how your C preprocessor is invoked..."
cat <<'EOT' >testcpp.c
#define ABC abc
#define XYZ xyz
ABC.XYZ
EOT
echo 'Maybe "cc -E" will work...'
cc -E testcpp.c >testcpp.out 2>&1
if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
    echo "Yup, it does."
    cpp='cc -E'
else
    echo 'Nope...maybe "cc -P" will work...'
    cc -P testcpp.c >testcpp.out 2>&1
    if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
	echo "Yup, that does."
	cpp='cc -P'
    else
	echo 'Nixed again...maybe "/lib/cpp" will work...'
	/lib/cpp testcpp.c >testcpp.out 2>&1
	if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
	    echo "Hooray, it works!  I was beginning to wonder."
	    cpp='/lib/cpp'
	else
	    echo 'Hmm...maybe you already told me...'
	    case "$cpp" in
	    '') ;;
	    *) $cpp testcpp.c >testcpp.out 2>&1;;
	    esac
	    if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
		echo "Hooray, you did!  I was beginning to wonder."
	    else
		echo $n "Nope. I can't find a C preprocessor.  Name one: $c"
		rp='Name a C preprocessor:'
		read ans
		cpp="$ans"
		$cpp testcpp.c >testcpp.out 2>&1
		if $contains 'abc.xyz' testcpp.out >/dev/null 2>&1 ; then
		    echo "OK, that will do."
		else
		    echo "Sorry, I can't get that to work.  Go find one."
		    exit 1
		fi
	    fi
	fi
    fi
fi
rm -f testcpp.c testcpp.out

: get C preprocessor symbols handy
echo " "
cat <<'EOT' >Cppsym.c
char *sym[] = {
#ifdef mc68000
	"mc68000",
#endif
#ifdef sun
	"sun",
#endif
#ifdef gcos
	"gcos",
#endif
#ifdef unix
	"unix",
#endif
#ifdef ibm
	"ibm",
#endif
#ifdef gimpel
	"gimpel",
#endif
#ifdef interdata
	"interdata",
#endif
#ifdef tss
	"tss",
#endif
#ifdef os
	"os",
#endif
#ifdef mert
	"mert",
#endif
#ifdef pyr
	"pyr",
#endif
#ifdef vax
	"vax",
#endif
#ifdef pdp11
	"pdp11",
#endif
#ifdef i8086
	"i8086",
#endif
#ifdef z8000
	"z8000",
#endif
#ifdef 3b2
	"3b2",
#endif
#ifdef 3b5
	"3b5",
#endif
#ifdef 3b20
	"3b20",
#endif
#ifdef 3b200
	"3b200",
#endif
0};
main(argc,argv)
int argc;
char **argv;
{
    int i;

    for (argc--,argv++; argc; argc--,argv++) {
	for (i=0; sym[i]; i++) {
	    if (strcmp(argv[0],sym[i]) == 0)
		exit(0);
	}
    }
    exit(1);
}
EOT
echo "Your machine appears to have the following attributes:"
$cpp Cppsym.c | sed -n -e 's/^	"\(.*\)",$/\1/p'
cc Cppsym.c -o Cppsym
rm -f Cppsym.c

: see how many register declarations we want to use
case "$registers" in
'')
    if Cppsym pdp11 i8086 z8000; then
	dflt=3
    else
	if Cppsym sun mc68000; then
	    dflt=10
	else
	    : if you have any other numbers for me, send them in
	    dflt=6
	fi
    fi
    ;;
*)  dflt=$registers ;;
esac
cat <<EOM
 
Different C compilers on different machines pay attention to different
numbers of register declarations.  About how many register declarations in
EOM
$echo $n "each routine does your C compiler pay attention to? (OK to guess) [$dflt] $c"
rp="# register declarations used? [$dflt]"
read ans
case "$ans" in
'') ans=$dflt;;
esac
registers=$ans
reg1=''
awk "END { for (i=1; i<=16; i++) printf \"reg%d=''\n\", i}" </dev/null >.foo
. .foo
awk "END { for (i=1; i<=$registers; i++) printf \"reg%d=register\n\", i}" \
	</dev/null >.foo
. .foo
rm -f .foo

: preserve RCS keywords in files with variable substitution, grrr
Log='$Log'
Header='$Header'

: set up shell script to do ~ expansion
cat >filexp <<EOSS
$startsh
: expand filename
case "\$1" in
~/*|~)
    $echo \$1 | $sed "s|~|\${HOME-\$LOGDIR}|"
    ;;
~*)
    if $test -f /bin/csh; then
	/bin/csh -f -c "glob \$1"
	$echo ""
    else
	name=\`$expr x\$1 : '..\([^/]*\)'\`
	dir=\`$sed </etc/passwd -n -e "/^\${name}:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\).*"'\$'"/\1/" -e p -e q -e '}'\`
	if $test ! -d "\$dir"; then
	    me=\`basename \$0\`
	    $echo "\$me: can't locate home directory for: \$name" >&2
	    exit 1
	fi
	case "\$1" in
	*/*)
	    $echo \$dir/\`$expr x\$1 : '..[^/]*/\(.*\)'\`
	    ;;
	*)
	    $echo \$dir
	    ;;
	esac
    fi
    ;;
*)
    $echo \$1
    ;;
esac
EOSS
chmod 755 filexp
$eunicefix filexp

: determine where public executables go
case "$bin" in
'')
    dflt=`loc . /bin /usr/local/bin /usr/lbin /usr/local /usr/bin`
    ;;
*)  dflt="$bin"
    ;;
esac
bin='blurfl/dyick'
while $test ! -d "$bin" ; do
    case "$bin" in
      blurfl*) ;;
      *) $echo "$bin does not appear to exist." ;;
    esac
    $echo " "
    rp="Where do you want to put the public executables? [$dflt]"
    $echo $n "$rp $c"
    read ans
    bin="$ans"
    bin=`filexp $bin`
    case "$bin" in
      '') bin=$dflt ;;
    esac
done

: determine where manual pages go
case "$mansrc" in
'')
    dflt=`loc . /usr/man/man1 /usr/man/mann /usr/man/local/man1 /usr/man/u_man/man1 /usr/man/man1`
    ;;
*)  dflt="$mansrc"
    ;;
esac
mansrc='blurfl/dyick'
while $test ! -d "$mansrc" ; do
    case "$mansrc" in
      blurfl*) ;;
      *) $echo "$mansrc does not appear to exist." ;;
    esac
    $echo " "
    rp="Where do the manual pages (source) go? [$dflt]"
    $echo $n "$rp $c"
    read ans
    mansrc=`filexp "$ans"`
    case "$mansrc" in
      '') mansrc=$dflt ;;
    esac
done
case "$mansrc" in
*l)
    manext=l
    ;;
*n)
    manext=n
    ;;
*)
    manext=1
    ;;
esac

: see if we need a special compiler
$echo " "
if usg; then
    case "$cc" in
    '')
	case "$Mcc" in
	/*) dflt='Mcc'
	    ;;
	*)
	    if $contains '\-M' $mansrc/cc.1 >/dev/null 2>&1 ; then
		dflt='cc -M'
	    else
		dflt='cc'
	    fi
	    ;;
	esac
	;;
    *)  dflt="$cc";;
    esac
    $cat <<'EOM'
 
On some systems the default C compiler will not resolve multiple global
references that happen to have the same name.  On some such systems the
"Mcc" command may be used to force these to be resolved.  On other systems
a "cc -M" command is required.  What command will force resolution on
EOM
    $echo $n "this system? [$dflt] $c"
    rp="Command to resolve multiple refs? [$dflt]"
    read ans
    cc="$ans"
    case "$cc" in
	'') cc="$dflt" ;;
    esac
else
    $echo "Not a USG system--assuming cc can resolve multiple definitions."
    cc=cc
fi

: see if we should throw a -i into the Makefile
$echo " "
if Cppsym pdp11 i8086 z8000; then
    if $contains '\-i' $mansrc/cc.1 >/dev/null 2>&1 ; then
	rp="Your system appears to have separate I and D space.  Is this true? [y]"
	$echo $n "$rp $c"
	read ans
	case "$ans" in
	    n*|f*) iandd='' ;;
	    *)     iandd='-i' ;;
	esac
    else
	$echo "Your system appears to NOT have separate I and D space."
	$echo $n "Is this correct? [y] $c"
	rp='No separate I and D.  Correct? [y]'
	read ans
	case "$ans" in
	    n*|f*) iandd='-i' ;;
	    *)     iandd='' ;;
	esac
    fi
else
    $echo $n "Does your machine have separate I and D space? [n] $c"
    read ans
    case "$ans" in
	y*)    iandd='-i' ;;
	*)     iandd='' ;;
    esac
fi

$echo " "
$echo "End of configuration questions."
$echo " "

: create config.sh file
$echo " "
$echo "Creating config.sh..."
$spitshell <<EOT >config.sh
$startsh
# config.sh
# This file was produced by running the Configure script.

d_eunice='$d_eunice'
eunicefix='$eunicefix'
loclist='$loclist'
expr='$expr'
sed='$sed'
echo='$echo'
cat='$cat'
rm='$rm'
mv='$mv'
cp='$cp'
tail='$tail'
tr='$tr'
mkdir='$mkdir'
sort='$sort'
uniq='$uniq'
grep='$grep'
trylist='$trylist'
test='$test'
inews='$inews'
egrep='$egrep'
more='$more'
pg='$pg'
Mcc='$Mcc'
vi='$vi'
mailx='$mailx'
Log='$Log'
Header='$Header'
bin='$bin'
cc='$cc'
contains='$contains'
cpp='$cpp'
d_index='$d_index'
d_void='$d_void'
iandd='$iandd'
libc='$libc'
mansrc='$mansrc'
manext='$manext'
n='$n'
c='$c'
package='$package'
registers='$registers'
reg1='$reg1'
reg2='$reg2'
reg3='$reg3'
reg4='$reg4'
reg5='$reg5'
reg6='$reg6'
reg7='$reg7'
reg8='$reg8'
reg9='$reg9'
reg10='$reg10'
reg11='$reg11'
reg12='$reg12'
reg13='$reg13'
reg14='$reg14'
reg15='$reg15'
reg16='$reg16'
spitshell='$spitshell'
shsharp='$shsharp'
sharpbang='$sharpbang'
startsh='$startsh'
CONFIG=true
EOT
 
: create config.h file
$echo " "
$echo "Creating config.h..."
$cat <<EOT >config.h
/* config.h
 * This file was produced by running the Configure script.
 * Feel free to modify any of this as the need arises.
 */


#$d_eunice	EUNICE		/* no file linking? */
#$d_eunice	VMS		/* other assorted ickies? */

#$d_index	index strchr	/* cultural */
#$d_index	rindex strrchr	/*  differences? */

#$d_void	void int	/* is void to be avoided? */

/* How many register declarations are paid attention to? */

#define Reg1 $reg1		/**/
#define Reg2 $reg2		/**/
#define Reg3 $reg3		/**/
#define Reg4 $reg4		/**/
#define Reg5 $reg5		/**/
#define Reg6 $reg6		/**/
#define Reg7 $reg7		/**/
#define Reg8 $reg8		/**/
#define Reg9 $reg9		/**/
#define Reg10 $reg10		/**/
#define Reg11 $reg11		/**/
#define Reg12 $reg12		/**/
#define Reg13 $reg13		/**/
#define Reg14 $reg14		/**/
#define Reg15 $reg15		/**/
#define Reg16 $reg16		/**/

EOT
CONFIG=true

if $contains '\.SH' MANIFEST >/dev/null 2>&1; then
    $echo " "
    $echo "Doing variable substitutions on .SH files..."
    set `$grep <MANIFEST '\.SH' | awk '{print $1}'`
    for file in $*; do
	case "$file" in
	*/*)
	    dir=`$expr X$file : 'X\(.*\)/'`
	    file=`$expr X$file : 'X.*/\(.*\)'`
	    (cd $dir && . $file)
	    ;;
	*)
	    . $file
	    ;;
	esac
    done
fi

if $contains '^depend:' Makefile >/dev/null 2>&1; then
    $echo " "
    $echo 'Now you need to generate make dependencies by running "make depend".'
    $echo 'You might prefer to run it in background: "make depend > makedepend.out &"'
    $echo $n "Would you like me to run it for you (it takes quite a while)? [n] $c" 
    rp="Run make depend now? [n]"
    read ans
    case "$ans" in
    y*) make depend;;
    esac
fi

$rm -f libc.list kit*isdone bsd usg v7 eunice loc Cppsym

if test -f Makefile; then
    $echo " "
    $echo "Now you must run a make."
else
    $echo "Done."
fi
: end of Configure
SHAR_EOF
if test 21237 -ne "`wc -c < 'Configure'`"
then
	echo shar: error transmitting "'Configure'" '(should have been 21237 characters)'
fi
chmod +x 'Configure'
fi # end of overwriting check
echo shar: extracting "'EXTERN.h'" '(241 characters)'
if test -f 'EXTERN.h'
then
	echo shar: will not over-write existing file "'EXTERN.h'"
else
cat << \SHAR_EOF > 'EXTERN.h'
/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
 *
 * $Log:	EXTERN.h,v $
 * Revision 2.0  86/09/17  15:35:37  lwall
 * Baseline for netwide release.
 * 
 */

#undef EXT
#define EXT extern

#undef INIT
#define INIT(x)

#undef DOINIT
SHAR_EOF
if test 241 -ne "`wc -c < 'EXTERN.h'`"
then
	echo shar: error transmitting "'EXTERN.h'" '(should have been 241 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'INTERN.h'" '(239 characters)'
if test -f 'INTERN.h'
then
	echo shar: will not over-write existing file "'INTERN.h'"
else
cat << \SHAR_EOF > 'INTERN.h'
/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
 *
 * $Log:	INTERN.h,v $
 * Revision 2.0  86/09/17  15:35:58  lwall
 * Baseline for netwide release.
 * 
 */

#undef EXT
#define EXT

#undef INIT
#define INIT(x) = x

#define DOINIT
SHAR_EOF
if test 239 -ne "`wc -c < 'INTERN.h'`"
then
	echo shar: error transmitting "'INTERN.h'" '(should have been 239 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile'" '(1372 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
###############################################################################
##									     ##
##	File:     Makefile						     ##
##	Altered-by:   Frank Wortner					     ##
##	Created:  Fri May 27 09:47:49 1988				     ##
##	Contents: A Makefile for Patch Under Minix			     ##
##									     ##
##	$Log$								     ##
###############################################################################
CC = cc
bin = /usr/bin
mansrc = /usr/doc
manext = l
CFLAGS =  -DMINIX
LDFLAGS = -i


public = patch
libs = 
private = 
defs =
manpages = patch.man
util = Makefile

c = patch.c pch.c inp.c version.c util.c

obj = patch.s pch.s inp.s util.s version.s


all: $(public) $(private) $(util)
	touch all

patch: $(obj)
	$(CC) $(LDFLAGS) $(obj) $(libs) -o patch

# won't work with csh
install: patch
	export PATH || exit 1
	- mv $(bin)/patch $(bin)/patch.old
	- if test `pwd` != $(bin); then cp $(public) $(bin); fi
	cd $(bin); chmod 755 $(public)
	- if test `pwd` != $(mansrc); then \
for page in $(manpages); do \
cp $$page $(mansrc)/`basename $$page .man`.$(manext); \
done; \
fi

clean:
	rm -f *.s *.orig core

patch.s: config.h common.h patch.c inp.h pch.h util.h version.h
pch.s: config.h common.h pch.c pch.h util.h
inp.s: config.h common.h inp.c inp.h util.h
util.s: config.h common.h util.c util.h
version.s: config.h common.h version.c version.h patchlevel.h util.h
SHAR_EOF
if test 1372 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 1372 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.SH'" '(1954 characters)'
if test -f 'Makefile.SH'
then
	echo shar: will not over-write existing file "'Makefile.SH'"
else
cat << \SHAR_EOF > 'Makefile.SH'
case $CONFIG in
    '') . config.sh ;;
esac
echo "Extracting Makefile (with variable substitutions)"
cat >Makefile <<!GROK!THIS!
# $Header: Makefile.SH,v 2.0 86/09/17 15:36:15 lwall Exp $
#
# $Log:	Makefile.SH,v $
# Revision 2.0  86/09/17  15:36:15  lwall
# Baseline for netwide release.
# 
# Revision 1.2  86/09/08  14:07:42  lwall
# Split up patch.c.
# 
# Revision 1.1  86/08/01  20:18:35  lwall
# Initial revision
# 

CC = $cc
bin = $bin
mansrc = $mansrc
manext = $manext
CFLAGS = $iandd -O
LDFLAGS = $iandd

!GROK!THIS!
cat >>Makefile <<'!NO!SUBS!'

public = patch
private = 
manpages = patch.man
util = Makefile

c = patch.c pch.c inp.c version.c util.c

obj = patch.o pch.o inp.o util.o version.o

lintflags = -phbvxac

addedbyconf = Makefile.old bsd config.h config.sh eunice loc pdp11 usg v7

# grrr
SHELL = /bin/sh

.c.o:
	$(CC) -c $(CFLAGS) $*.c

all: $(public) $(private) $(util)
	touch all

patch: $(obj)
	$(CC) $(LDFLAGS) $(obj) $(libs) -o patch

# won't work with csh
install: patch
	export PATH || exit 1
	- mv $(bin)/patch $(bin)/patch.old
	- if test `pwd` != $(bin); then cp $(public) $(bin); fi
	cd $(bin); chmod 755 $(public)
	- if test `pwd` != $(mansrc); then \
for page in $(manpages); do \
cp $$page $(mansrc)/`basename $$page .man`.$(manext); \
done; \
fi

clean:
	rm -f *.o *.orig core

realclean:
	rm -f patch *.o *.orig core $(addedbyconf)

# The following lint has practically everything turned on.  Unfortunately,
# you have to wade through a lot of mumbo jumbo that can't be suppressed.
# If the source file has a /*NOSTRICT*/ somewhere, ignore the lint message
# for that spot.

lint:
	lint $(lintflags) $(defs) $(c) > patch.fuzz

patch.o: config.h common.h patch.c inp.h pch.h util.h version.h
pch.o: config.h common.h pch.c pch.h util.h
inp.o: config.h common.h inp.c inp.h util.h
util.o: config.h common.h util.c util.h
version.o: config.h common.h version.c version.h patchlevel.h util.h

!NO!SUBS!
$eunicefix Makefile
SHAR_EOF
if test 1954 -ne "`wc -c < 'Makefile.SH'`"
then
	echo shar: error transmitting "'Makefile.SH'" '(should have been 1954 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'READ-ME-FIRST'" '(2099 characters)'
if test -f 'READ-ME-FIRST'
then
	echo shar: will not over-write existing file "'READ-ME-FIRST'"
else
cat << \SHAR_EOF > 'READ-ME-FIRST'
This is the source to Larry Wall's "patch" program ported to the 
Minix operating system.  I've used this program for several months,
and it seems to work quite well.  It certainly is more reliable and
forgiving than "fix."  That program can't reconcile diffs with
altered source;  this one can.

There are a number of problems with the "virgin" Un*x source under
Minix.  The first is the absence of both "sed" and a full
implementation of "expr" from off-the-shelf Minix
1.2.  This means that "Configure" can't run to completion under Minix.
I've pre-run Configure and enclosed the results, so this won't
be a problem.  All you have to do is type "make."

Another problem arises from patch's use of long integers as indices
into character arrays.  The Minix C compiler "knows" that it has at
most 64K worth of memory to play with, so it prints messages about
conversions from long to pointer losing accuracy.  At *lot* of
messages.  Don't worry.  I've been using the program for a couple of
months and it does work in spite of the nasty compilation warnings.
I've tracked down the problem to one line in common.h:

	typedef long LINENUM;

Don't bother trying to change long to int;  I've tried that.  The
warnings disappear, but the program malfunctions.  I'll take
compilation warnings over incorrect operation any day.

Patch occasionally uses "ed" to process diffs that look like editor
scripts.  Someone (Brian Beatie, I think) posted an ed a while ago
and the sources should be in the achives.  I've assumed that ed lives in
/usr/bin.

A final note to the "small is beautiful" fans:  yes, I know that patch is
quite large.  It is not used constantly, and it eliminates a lot of
frustration.  It's memory well spent.

A final plea:  I've tried contacting Larry Wall, but to no avail.  I'd
like to see "official" support for Minix patch.  For one thing, it
would assure that Minix users would always have the latest version.
Does anyone know his current e-mail address?

Enjoy!

				Frank Wortner
				Morgan Stanley & Co.
				(212) 703-6498

				frank@morgan.com
				...{sun, uunet}!mstan!frank
SHAR_EOF
if test 2099 -ne "`wc -c < 'READ-ME-FIRST'`"
then
	echo shar: error transmitting "'READ-ME-FIRST'" '(should have been 2099 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(2963 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
			Patch Kit, Version 2.0

		    Copyright (c) 1986, Larry Wall

You may copy the patch kit in whole or in part as long as you don't try to
make money off it, or pretend that you wrote it.
--------------------------------------------------------------------------

Please read all the directions below before you proceed any further, and
then follow them carefully.  Failure to do so may void your warranty. :-)

After you have unpacked your kit, you should have all the files listed
in MANIFEST.

Installation

1)  Run Configure.  This will figure out various things about your system.
    Some things Configure will figure out for itself, other things it will
    ask you about.  It will then proceed to make config.h, config.sh, and
    Makefile.

    You might possibly have to trim # comments from the front of Configure
    if your sh doesn't handle them, but all other # comments will be taken
    care of.

    If you don't have sh, you'll have to rip the prototype of config.h out
    of Configure and generate the defines by hand.

2)  Glance through config.h to make sure system dependencies are correct.
    Most of them should have been taken care of by running the Configure script.

    If you have any additional changes to make to the C definitions, they
    can be done in the Makefile, or in config.h.  Bear in mind that they may
    get undone next time you run Configure.

3)  make

    This will attempt to make patch in the current directory.

4)  make install

    This will put patch into a public directory (normally /usr/local/bin).
    It will also try to put the man pages in a reasonable place.  It will not
    nroff the man page, however.

5)  Read the manual entry before running patch.

6)  IMPORTANT!  Help save the world!  Communicate any problems and
    suggested patches to me, lwall@sdcrdcf.UUCP (Larry Wall), so we can
    keep the world in sync.  If you have a problem, there's someone else
    out there who either has had or will have the same problem.

    If possible, send in patches such that the patch program will apply them.
    Context diffs are the best, then normal diffs.  Don't send ed scripts--
    I've probably changed my copy since the version you have.

    Watch for patch patches in net.sources.bugs.  Patches will generally be
    in a form usable by the patch program.  If you are just now bringing up
    patch and aren't sure how many patches there are, write to me and I'll
    send any you don't have.  Your current patch level is shown in patchlevel.h.


NEW FEATURES IN THIS RELEASE

(Correct) support for 4.3bsd-style context diffs.
Files can be created from scratch.
You can specify a fuzz-factor for context matching.
You can force patch to ask no questions.
You can specify how much of the leading pathname to strip off filenames.
Uses a Configure script for greater portability.
You are now asked if you want to apply a reversed patch.
No limit (apart from memory) on the size of hunks.
SHAR_EOF
if test 2963 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 2963 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'common.h'" '(3604 characters)'
if test -f 'common.h'
then
	echo shar: will not over-write existing file "'common.h'"
else
cat << \SHAR_EOF > 'common.h'
/* $Header: common.h,v 2.0 86/09/17 15:36:39 lwall Exp $
 *
 * $Log:	common.h,v $
 * Revision 2.0  86/09/17  15:36:39  lwall
 * Baseline for netwide release.
 * 
 */

#define DEBUGGING

#include "config.h"

/* shut lint up about the following when return value ignored */

#define Signal (void)signal
#define Unlink (void)unlink
#define Lseek (void)lseek
#define Fseek (void)fseek
#define Fstat (void)fstat
#define Pclose (void)pclose
#define Close (void)close
#define Fclose (void)fclose
#define Fflush (void)fflush
#define Sprintf (void)sprintf
#define Mktemp (void)mktemp
#define Strcpy (void)strcpy
#define Strcat (void)strcat

#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <stat.h>
#include <ctype.h>
#include <signal.h>

/* constants */

#define TRUE (1)
#define FALSE (0)

#define MAXHUNKSIZE 100000		/* is this enough lines? */
#define INITHUNKMAX 125			/* initial dynamic allocation size */
#define MAXLINELEN 1024
#define BUFFERSIZE 1024
#define ORIGEXT ".orig"
#define SCCSPREFIX "s."
#define GET "get -e %s"
#define RCSSUFFIX ",v"
#define CHECKOUT "co -l %s"

/* handy definitions */

#define Null(t) ((t)0)
#define Nullch Null(char *)
#define Nullfp Null(FILE *)
#define Nulline Null(LINENUM)

#define Ctl(ch) ((ch) & 037)

#define strNE(s1,s2) (strcmp(s1, s2))
#define strEQ(s1,s2) (!strcmp(s1, s2))
#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))

/* typedefs */

typedef char bool;
typedef int LINENUM;			/* must be signed */
typedef unsigned MEM;			/* what to feed malloc */

/* globals */

EXT int Argc;				/* guess */
EXT char **Argv;
EXT int Argc_last;			/* for restarting plan_b */
EXT char **Argv_last;

EXT struct stat filestat;		/* file statistics area */
EXT int filemode INIT(0644);

EXT char buf[MAXLINELEN];		/* general purpose buffer */
EXT FILE *ofp INIT(Nullfp);		/* output file pointer */
EXT FILE *rejfp INIT(Nullfp);		/* reject file pointer */

EXT bool using_plan_a INIT(TRUE);	/* try to keep everything in memory */
EXT bool out_of_mem INIT(FALSE);	/* ran out of memory in plan a */

#define MAXFILEC 2
EXT int filec INIT(0);			/* how many file arguments? */
EXT char *filearg[MAXFILEC];
EXT bool ok_to_create_file INIT(FALSE);
EXT char *bestguess INIT(Nullch);	/* guess at correct filename */

EXT char *outname INIT(Nullch);
EXT char rejname[128];

EXT char *origext INIT(Nullch);

EXT char TMPOUTNAME[] INIT("/tmp/patchoXXXXXX");
EXT char TMPINNAME[] INIT("/tmp/patchiXXXXXX");	/* might want /usr/tmp here */
EXT char TMPREJNAME[] INIT("/tmp/patchrXXXXXX");
EXT char TMPPATNAME[] INIT("/tmp/patchpXXXXXX");
EXT bool toutkeep INIT(FALSE);
EXT bool trejkeep INIT(FALSE);

EXT LINENUM last_offset INIT(0);
#ifdef DEBUGGING
EXT int debug INIT(0);
#endif
EXT LINENUM maxfuzz INIT(2);
EXT bool force INIT(FALSE);
EXT bool verbose INIT(TRUE);
EXT bool reverse INIT(FALSE);
EXT bool noreverse INIT(FALSE);
EXT bool skip_rest_of_patch INIT(FALSE);
EXT int strippath INIT(957);
EXT bool canonicalize INIT(FALSE);

#define CONTEXT_DIFF 1
#define NORMAL_DIFF 2
#define ED_DIFF 3
#define NEW_CONTEXT_DIFF 4
EXT int diff_type INIT(0);

EXT bool do_defines INIT(FALSE);	/* patch using ifdef, ifndef, etc. */
EXT char if_defined[128];		/* #ifdef xyzzy */
EXT char not_defined[128];		/* #ifndef xyzzy */
EXT char else_defined[] INIT("#else\n");/* #else */
EXT char end_defined[128];		/* #endif xyzzy */

EXT char *revision INIT(Nullch);	/* prerequisite revision, if any */

char *malloc();
char *realloc();
char *strcpy();
char *strcat();
char *sprintf();		/* usually */
long atol();
long lseek();
char *mktemp();
SHAR_EOF
if test 3604 -ne "`wc -c < 'common.h'`"
then
	echo shar: error transmitting "'common.h'" '(should have been 3604 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'config.h'" '(857 characters)'
if test -f 'config.h'
then
	echo shar: will not over-write existing file "'config.h'"
else
cat << \SHAR_EOF > 'config.h'
/* config.h
 * This file was produced by running the Configure script.
 * Feel free to modify any of this as the need arises.
 */

/*undef	EUNICE		/* no file linking? */
/*undef	VMS		/* other assorted ickies? */

/*undef	index strchr	/* cultural */
/*undef	rindex strrchr	/*  differences? */

/*undef	void int	/* is void to be avoided? */

/* How many register declarations are paid attention to? */

#define Reg1 register		/**/
#define Reg2 register		/**/
#define Reg3 register		/**/
#define Reg4 register		/**/
#define Reg5 register		/**/
#define Reg6 register		/**/
#define Reg7 register		/**/
#define Reg8 register		/**/
#define Reg9 register		/**/
#define Reg10 register		/**/
#define Reg11 register		/**/
#define Reg12 register		/**/
#define Reg13 register		/**/
#define Reg14 register		/**/
#define Reg15 register		/**/
#define Reg16 register		/**/

SHAR_EOF
if test 857 -ne "`wc -c < 'config.h'`"
then
	echo shar: error transmitting "'config.h'" '(should have been 857 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'inp.c'" '(7942 characters)'
if test -f 'inp.c'
then
	echo shar: will not over-write existing file "'inp.c'"
else
cat << \SHAR_EOF > 'inp.c'
/* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
 *
 * $Log:	inp.c,v $
 * Revision 2.0  86/09/17  15:37:02  lwall
 * Baseline for netwide release.
 * 
 */

#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "pch.h"
#include "INTERN.h"
#include "inp.h"

/* Input-file-with-indexable-lines abstract type */

static long i_size;			/* size of the input file */
static char *i_womp;			/* plan a buffer for entire file */
static char **i_ptr;			/* pointers to lines in i_womp */

static int tifd = -1;			/* plan b virtual string array */
static char *tibuf[2];			/* plan b buffers */
static LINENUM tiline[2] = {-1, -1};	/* 1st line in each buffer */
static LINENUM lines_per_buf;		/* how many lines per buffer */
static int tireclen;			/* length of records in tmp file */

/* New patch--prepare to edit another file. */

void
re_input()
{
    if (using_plan_a) {
	i_size = 0;
#ifndef lint
	if (i_ptr != Null(char**))
	    free((char *)i_ptr);
#endif
	if (i_womp != Nullch)
	    free(i_womp);
	i_womp = Nullch;
	i_ptr = Null(char **);
    }
    else {
	using_plan_a = TRUE;		/* maybe the next one is smaller */
	Close(tifd);
	tifd = -1;
	free(tibuf[0]);
	free(tibuf[1]);
	tibuf[0] = tibuf[1] = Nullch;
	tiline[0] = tiline[1] = -1;
	tireclen = 0;
    }
}

/* Constuct the line index, somehow or other. */

void
scan_input(filename)
char *filename;
{
    if (!plan_a(filename))
	plan_b(filename);
    if (verbose) {
	say3("Patching file %s using Plan %s...\n", filename,
	  (using_plan_a ? "A" : "B") );
    }
}

/* Try keeping everything in memory. */

bool
plan_a(filename)
char *filename;
{
    int ifd;
    Reg1 char *s;
    Reg2 LINENUM iline;

    if (ok_to_create_file && stat(filename, &filestat) < 0) {
	if (verbose)
	    say2("(Creating file %s...)\n",filename);
	makedirs(filename, TRUE);
	close(creat(filename, 0666));
    }
    if (stat(filename, &filestat) < 0) {
	Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
	if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
	    Sprintf(buf, CHECKOUT, filename);
	    if (verbose)
		say2("Can't find %s--attempting to check it out from RCS.\n",
		    filename);
	    if (system(buf) || stat(filename, &filestat))
		fatal2("Can't check out %s.\n", filename);
	}
	else {
	    Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
	    if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
		Sprintf(buf, GET, filename);
		if (verbose)
		    say2("Can't find %s--attempting to get it from SCCS.\n",
			filename);
		if (system(buf) || stat(filename, &filestat))
		    fatal2("Can't get %s.\n", filename);
	    }
	    else
		fatal2("Can't find %s.\n", filename);
	}
    }
    filemode = filestat.st_mode;
    if ((filemode & S_IFMT) & ~S_IFREG)
	fatal2("%s is not a normal file--can't patch.\n", filename);
    i_size = filestat.st_size;
    if (out_of_mem) {
	set_hunkmax();		/* make sure dynamic arrays are allocated */
	out_of_mem = FALSE;
	return FALSE;			/* force plan b because plan a bombed */
    }
#ifdef lint
    i_womp = Nullch;
#else
    i_womp = malloc((MEM)(i_size+2));	/* lint says this may alloc less than */
					/* i_size, but that's okay, I think. */
#endif
    if (i_womp == Nullch)
	return FALSE;
    if ((ifd = open(filename, 0)) < 0)
	fatal2("Can't open file %s\n", filename);
#ifndef lint
    if (read(ifd, i_womp, (int)i_size) != i_size) {
	Close(ifd);	/* probably means i_size > 15 or 16 bits worth */
	free(i_womp);	/* at this point it doesn't matter if i_womp was */
	return FALSE;	/*   undersized. */
    }
#endif
    Close(ifd);
    if (i_size && i_womp[i_size-1] != '\n')
	i_womp[i_size++] = '\n';
    i_womp[i_size] = '\0';

    /* count the lines in the buffer so we know how many pointers we need */

    iline = 0;
    for (s=i_womp; *s; s++) {
	if (*s == '\n')
	    iline++;
    }
#ifdef lint
    i_ptr = Null(char**);
#else
    i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
#endif
    if (i_ptr == Null(char **)) {	/* shucks, it was a near thing */
	free((char *)i_womp);
	return FALSE;
    }
    
    /* now scan the buffer and build pointer array */

    iline = 1;
    i_ptr[iline] = i_womp;
    for (s=i_womp; *s; s++) {
	if (*s == '\n')
	    i_ptr[++iline] = s+1;	/* these are NOT null terminated */
    }
    input_lines = iline - 1;

    /* now check for revision, if any */

    if (revision != Nullch) { 
	if (!rev_in_string(i_womp)) {
	    if (force) {
		if (verbose)
		    say2("\
Warning: this file doesn't appear to be the %s version--patching anyway.\n",
			revision);
	    }
	    else {
		ask2("\
This file doesn't appear to be the %s version--patch anyway? [n] ",
		    revision);
	    if (*buf != 'y')
		fatal1("Aborted.\n");
	    }
	}
	else if (verbose)
	    say2("Good.  This file appears to be the %s version.\n",
		revision);
    }
    return TRUE;			/* plan a will work */
}

/* Keep (virtually) nothing in memory. */

void
plan_b(filename)
char *filename;
{
    Reg3 FILE *ifp;
    Reg1 int i = 0;
    Reg2 int maxlen = 1;
    Reg4 bool found_revision = (revision == Nullch);

    using_plan_a = FALSE;
    if ((ifp = fopen(filename, "r")) == Nullfp)
	fatal2("Can't open file %s\n", filename);
    if ((tifd = creat(TMPINNAME, 0666)) < 0)
	fatal2("Can't open file %s\n", TMPINNAME);
    while (fgets(buf, sizeof buf, ifp) != Nullch) {
	if (revision != Nullch && !found_revision && rev_in_string(buf))
	    found_revision = TRUE;
	if ((i = strlen(buf)) > maxlen)
	    maxlen = i;			/* find longest line */
    }
    if (revision != Nullch) {
	if (!found_revision) {
	    if (force) {
		if (verbose)
		    say2("\
Warning: this file doesn't appear to be the %s version--patching anyway.\n",
			revision);
	    }
	    else {
		ask2("\
This file doesn't appear to be the %s version--patch anyway? [n] ",
		    revision);
		if (*buf != 'y')
		    fatal1("Aborted.\n");
	    }
	}
	else if (verbose)
	    say2("Good.  This file appears to be the %s version.\n",
		revision);
    }
    Fseek(ifp, 0L, 0);		/* rewind file */
    lines_per_buf = BUFFERSIZE / maxlen;
    tireclen = maxlen;
    tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
    tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
    if (tibuf[1] == Nullch)
	fatal1("Can't seem to get enough memory.\n");
    for (i=1; ; i++) {
	if (! (i % lines_per_buf))	/* new block */
	    if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
		fatal1("patch: can't write temp file.\n");
	if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
	  == Nullch) {
	    input_lines = i - 1;
	    if (i % lines_per_buf)
		if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
		    fatal1("patch: can't write temp file.\n");
	    break;
	}
    }
    Fclose(ifp);
    Close(tifd);
    if ((tifd = open(TMPINNAME, 0)) < 0) {
	fatal2("Can't reopen file %s\n", TMPINNAME);
    }
}

/* Fetch a line from the input file, \n terminated, not necessarily \0. */

char *
ifetch(line,whichbuf)
Reg1 LINENUM line;
int whichbuf;				/* ignored when file in memory */
{
    if (line < 1 || line > input_lines)
	return "";
    if (using_plan_a)
	return i_ptr[line];
    else {
	LINENUM offline = line % lines_per_buf;
	LINENUM baseline = line - offline;

	if (tiline[0] == baseline)
	    whichbuf = 0;
	else if (tiline[1] == baseline)
	    whichbuf = 1;
	else {
	    tiline[whichbuf] = baseline;
#ifndef lint		/* complains of long accuracy */
	    Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0);
#endif
	    if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
		fatal2("Error reading tmp file %s.\n", TMPINNAME);
	}
	return tibuf[whichbuf] + (tireclen*offline);
    }
}

/* True if the string argument contains the revision number we want. */

bool
rev_in_string(string)
char *string;
{
    Reg1 char *s;
    Reg2 int patlen;

    if (revision == Nullch)
	return TRUE;
    patlen = strlen(revision);
    for (s = string; *s; s++) {
	if (isspace(*s) && strnEQ(s+1, revision, patlen) && 
		isspace(s[patlen+1] )) {
	    return TRUE;
	}
    }
    return FALSE;
}

SHAR_EOF
if test 7942 -ne "`wc -c < 'inp.c'`"
then
	echo shar: error transmitting "'inp.c'" '(should have been 7942 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'inp.h'" '(473 characters)'
if test -f 'inp.h'
then
	echo shar: will not over-write existing file "'inp.h'"
else
cat << \SHAR_EOF > 'inp.h'
/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
 *
 * $Log:	inp.h,v $
 * Revision 2.0  86/09/17  15:37:25  lwall
 * Baseline for netwide release.
 * 
 */

EXT LINENUM input_lines INIT(0);	/* how long is input file in lines */
EXT LINENUM last_frozen_line INIT(0);	/* how many input lines have been */
					/* irretractibly output */

bool rev_in_string();
void scan_input();
bool plan_a();			/* returns false if insufficient memory */
void plan_b();
char *ifetch();

SHAR_EOF
if test 473 -ne "`wc -c < 'inp.h'`"
then
	echo shar: error transmitting "'inp.h'" '(should have been 473 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'patch.doc'" '(15181 characters)'
if test -f 'patch.doc'
then
	echo shar: will not over-write existing file "'patch.doc'"
else
cat << \SHAR_EOF > 'patch.doc'



PATCH(1)                 USER COMMANDS                   PATCH(1)



NAME
     patch - a program for applying a diff file to an original

SYNOPSIS
     patch [options] orig patchfile [+ [options] orig]

     but usually just

     patch <patchfile

DESCRIPTION
     _P_a_t_c_h will take a patch file containing  any  of  the  three
     forms of difference listing produced by the _d_i_f_f program and
     apply those differences to an  original  file,  producing  a
     patched  version.  By default, the patched version is put in
     place of the original, with the original file backed  up  to
     the same name with the extension ".orig", or as specified by
     the -b switch.  You may also specify where you want the out-
     put  to go with a -o switch.  If _p_a_t_c_h_f_i_l_e is omitted, or is
     a hyphen, the patch will be read from standard input.

     Upon startup, patch will attempt to determine  the  type  of
     the  diff  listing,  unless  over-ruled  by  a -c, -e, or -n
     switch.  Context diffs and normal diffs are applied  by  the
     _p_a_t_c_h  program  itself, while ed diffs are simply fed to the
     _e_d editor via a pipe.

     _P_a_t_c_h will try to skip any leading garbage, apply the  diff,
     and  then skip any trailing garbage.  Thus you could feed an
     article or message containing a diff listing to  _p_a_t_c_h,  and
     it  should  work.   If the entire diff is indented by a con-
     sistent amount, this will be taken into account.

     With context diffs, and  to  a  lesser  extent  with  normal
     diffs,  _p_a_t_c_h  can detect when the line numbers mentioned in
     the patch are  incorrect,  and  will  attempt  to  find  the
     correct  place  to apply each hunk of the patch.  As a first
     guess, it takes the line number mentioned for the hunk, plus
     or  minus any offset used in applying the previous hunk.  If
     that is not the correct place, _p_a_t_c_h will scan both forwards
     and  backwards for a set of lines matching the context given
     in the hunk.  First _p_a_t_c_h looks for a place where all  lines
     of the context match.  If no such place is found, and it's a
     context diff, and the maximum fuzz factor is  set  to  1  or
     more,  then  another scan takes place ignoring the first and
     last line of context.  If that fails, and the  maximum  fuzz
     factor is set to 2 or more, the first two and last two lines
     of context are ignored, and  another  scan  is  made.   (The
     default  maximum  fuzz  factor is 2.) If _p_a_t_c_h cannot find a
     place to install that hunk of the patch,  it  will  put  the
     hunk out to a reject file, which normally is the name of the
     output file plus ".rej".  (Note that the rejected hunk  will



                       Last change: LOCAL                       1






PATCH(1)                 USER COMMANDS                   PATCH(1)



     come  out in context diff form whether the input patch was a
     context diff or a normal diff.  If the input  was  a  normal
     diff,  many  of  the contexts will simply be null.) The line
     numbers on the hunks in the reject  file  may  be  different
     than  in  the patch file: they reflect the approximate loca-
     tion patch thinks the failed hunks belong in  the  new  file
     rather than the old one.

     As each hunk is completed, you will be told whether the hunk
     succeeded  or failed, and which line (in the new file) _p_a_t_c_h
     thought the hunk should go on.  If this  is  different  from
     the  line  number specified in the diff you will be told the
     offset.  A single large offset MAY be an indication  that  a
     hunk  was  installed  in  the wrong place.  You will also be
     told if a fuzz factor was used to make the match,  in  which
     case you should also be slightly suspicious.

     If no original file is specified on the command line,  _p_a_t_c_h
     will  try  to  figure  out from the leading garbage what the
     name of the file to edit is.  In the  header  of  a  context
     diff,  the filename is found from lines beginning with "***"
     or "---", with the shortest name of an  existing  file  win-
     ning.  Only context diffs have lines like that, but if there
     is an "Index:" line in the leading garbage, _p_a_t_c_h  will  try
     to use the filename from that line.  The context diff header
     takes precedence over an Index line.  If no filename can  be
     intuited from the leading garbage, you will be asked for the
     name of the file to patch.

     (If the original file cannot be found, but a  suitable  SCCS
     or RCS file is handy, _p_a_t_c_h will attempt to get or check out
     the file.)

     Additionally, if the leading garbage contains a  "Prereq:  "
     line,  _p_a_t_c_h will take the first word from the prerequisites
     line (normally a version number) and check the input file to
     see  if  that word can be found.  If not, _p_a_t_c_h will ask for
     confirmation before proceeding.

     The upshot of all this is that you should be  able  to  say,
     while in a news interface, the following:

          | patch -d /usr/src/local/blurfl

     and patch a file in the blurfl directory directly  from  the
     article containing the patch.

     If the patch file contains more than one patch,  _p_a_t_c_h  will
     try  to  apply  each  of  them as if they came from separate
     patch files.  This means, among other  things,  that  it  is
     assumed  that  the  name of the file to patch must be deter-
     mined for each diff listing, and  that  the  garbage  before



                       Last change: LOCAL                       2






PATCH(1)                 USER COMMANDS                   PATCH(1)



     each  diff  listing  will be examined for interesting things
     such as filenames and revision level,  as  mentioned  previ-
     ously.   You  can  give  switches (and another original file
     name) for the second and subsequent  patches  by  separating
     the  corresponding  argument  lists by a '+'.  (The argument
     list for a second or subsequent patch may not specify a  new
     patch file, however.)

     _P_a_t_c_h recognizes the following switches:

     -b   causes the next  argument  to  be  interpreted  as  the
          backup extension, to be used in place of ".orig".

     -c   forces _p_a_t_c_h to interpret the patch file as  a  context
          diff.

     -d   causes _p_a_t_c_h to interpret the next argument as a direc-
          tory, and cd to it before doing anything else.

     -D   causes _p_a_t_c_h to use the "#ifdef...#endif" construct  to
          mark  changes.   The argument following will be used as
          the differentiating symbol.  Note that,  unlike  the  C
          compiler,  there must be a space between the -D and the
          argument.

     -e   forces _p_a_t_c_h to interpret  the  patch  file  as  an  ed
          script.

     -f   forces _p_a_t_c_h to assume that the user knows exactly what
          he  or  she is doing, and to not ask any questions.  It
          does not suppress  commentary,  however.   Use  -s  for
          that.

     -F<number>
          sets the maximum fuzz factor.  This switch only applied
          to context diffs, and causes _p_a_t_c_h to ignore up to that
          many lines in looking for places  to  install  a  hunk.
          Note  that a larger fuzz factor increases the odds of a
          faulty patch.  The default fuzz factor is 2, and it may
          not  be set to more than the number of lines of context
          in the context diff, ordinarily 3.

     -l   causes the pattern matching to be done loosely, in case
          the  tabs  and  spaces  have  been munged in your input
          file.  Any sequence of whitespace in the  pattern  line
          will  match  any  sequence  in  the input file.  Normal
          characters must still match exactly.  Each line of  the
          context must still match a line in the input file.

     -n   forces _p_a_t_c_h to interpret the patch file  as  a  normal
          diff.




                      Last change: LOCAL                       3






PATCH(1)                 USER COMMANDS                   PATCH(1)



     -N   causes _p_a_t_c_h to  ignore  patches  that  it  thinks  are
          reversed or already applied.  See also -R .

     -o   causes the next argument to be interpreted as the  out-
          put file name.

     -p<number>
          sets the pathname strip count, which controls how path-
          names  found in the patch file are treated, in case the
          you keep your files in a different directory  than  the
          person  who sent out the patch.  The strip count speci-
          fies how many backslashes are to be stripped  from  the
          front  of  the  pathname.   (Any  intervening directory
          names  also  go  away.)  For  example,  supposing   the
          filename in the patch file was

               /u/howard/src/blurfl/blurfl.c

          setting -p or -p0 gives the entire pathname unmodified,
          -p1 gives

               u/howard/src/blurfl/blurfl.c

          without the leading slash, -p4 gives

               blurfl/blurfl.c

          and not specifying -p at all just gives you "blurfl.c".
          Whatever  you  end  up with is looked for either in the
          current directory, or the directory specified by the -d
          switch.

     -r   causes the next  argument  to  be  interpreted  as  the
          reject file name.

     -R   tells _p_a_t_c_h that this patch was created  with  the  old
          and new files swapped.  (Yes, I'm afraid that does hap-
          pen occasionally, human nature being what it is.) _P_a_t_c_h
          will  attempt  to swap each hunk around before applying
          it.  Rejects will come out in the swapped format.   The
          -R  switch  will  not work with ed diff scripts because
          there is too  little  information  to  reconstruct  the
          reverse operation.

          If the first hunk of a patch fails, _p_a_t_c_h will  reverse
          the  hunk  to see if it can be applied that way.  If it
          can, you will be asked if  you  want  to  have  the  -R
          switch set.  If it can't, the patch will continue to be
          applied normally.  (Note: this method cannot  detect  a
          reversed  patch if it is a normal diff and if the first
          command is an  append  (i.e.  it  should  have  been  a
          delete)  since  appends always succeed, due to the fact



                       Last change: LOCAL                       4






PATCH(1)                 USER COMMANDS                   PATCH(1)



          that a null context will match anywhere.  Luckily, most
          patches add or change lines rather than delete them, so
          most reversed normal diffs will begin  with  a  delete,
          which will fail, triggering the heuristic.)

     -s   makes _p_a_t_c_h do  its  work  silently,  unless  an  error
          occurs.

     -S   causes _p_a_t_c_h to ignore this patch from the patch  file,
          but continue on looking for the next patch in the file.
          Thus

               patch -S + -S + <patchfile

          will ignore the first and second of three patches.

     -v   causes _p_a_t_c_h to print  out  it's  revision  header  and
          patch level.

     -x<number>
          sets internal debugging flags, and is of interest  only
          to _p_a_t_c_h patchers.

ENVIRONMENT
     No environment variables are used by _p_a_t_c_h.

FILES
     /tmp/patch*

SEE ALSO
     diff(1)

NOTES FOR PATCH SENDERS
     There are several things you should bear in mind if you  are
     going to be sending out patches.  First, you can save people
     a lot of grief by  keeping  a  patchlevel.h  file  which  is
     patched  to  increment  the patch level as the first diff in
     the patch file you send out.  If you put a Prereq:  line  in
     with the patch, it won't let them apply patches out of order
     without some warning.  Second, make  sure  you've  specified
     the  filenames  right,  either  in a context diff header, or
     with an Index: line.  If you are  patching  something  in  a
     subdirectory, be sure to tell the patch user to specify a -p
     switch as needed.  Third, you can create a file  by  sending
     out a diff that compares a null file to the file you want to
     create.  This will only work if the file you want to  create
     doesn't exist already in the target directory.  Fourth, take
     care not to send out reversed patches, since it makes people
     wonder whether they already applied the patch.  Fifth, while
     you may be able to get away with putting 582  diff  listings
     into one file, it is probably wiser to group related patches
     into separate files in case something goes haywire.



                       Last change: LOCAL                       5






PATCH(1)                 USER COMMANDS                   PATCH(1)



DIAGNOSTICS
     Too many to list here, but generally indicative  that  _p_a_t_c_h
     couldn't parse your patch file.

     The message "Hmm..." indicates  that  there  is  unprocessed
     text  in  the  patch  file  and  that _p_a_t_c_h is attempting to
     intuit whether there is a patch in that  text  and,  if  so,
     what kind of patch it is.

CAVEATS
     _P_a_t_c_h cannot tell if the line  numbers  are  off  in  an  ed
     script,  and  can  only  detect bad line numbers in a normal
     diff when it finds a "change" or a "delete" command.  A con-
     text  diff  using  fuzz  factor 3 may have the same problem.
     Until a suitable interactive interface is added, you  should
     probably  do  a  context  diff  in these cases to see if the
     changes made sense.  Of course, compiling without errors  is
     a  pretty  good  indication  that  the patch worked, but not
     always.

     _P_a_t_c_h usually produces the correct results, even when it has
     to   do  a  lot  of  guessing.   However,  the  results  are
     guaranteed to be correct only when the patch is  applied  to
     exactly the same version of the file that the patch was gen-
     erated from.

BUGS
     Could be smarter about partial matches, excessively  deviant
     offsets and swapped code, but that would take an extra pass.

     If code has been duplicated (for instance with  #ifdef  OLD-
     CODE  ... #else ...  #endif), _p_a_t_c_h is incapable of patching
     both versions, and, if it works at all,  will  likely  patch
     the wrong one, and tell you that it succeeded to boot.

     If you apply a patch  you've  already  applied,  _p_a_t_c_h  will
     think  it  is  a  reversed  patch, and offer to un-apply the
     patch.  This could be construed as a feature.

















                       Last change: LOCAL                       6


SHAR_EOF
echo shar: 205 control characters may be missing from "'patch.doc'"
if test 15181 -ne "`wc -c < 'patch.doc'`"
then
	echo shar: error transmitting "'patch.doc'" '(should have been 15181 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0

ncoverby@ndsuvax.UUCP (Glen Overby) (05/30/88)

In article <2766@louie.udel.EDU> frank@morgan.com (Frank Wortner) writes:
>Here is a version of Larry Wall's patch program.  I've made a few
>minor changes to get it to run under Minix.  The program has served me
>well over the past month or two and I'm reasonably confident that it
>works.


I, too, have been using patch on Minix since last summer (I can't remember
whose port of it I'm running), with no problems.  

I would like to note that the patch I use on our BSD Unxi VAX is at
patchlevel 9, whereas Frank's is at patchlevel 4.  I don't know what
bugs/features have been added/removed in the missing 5 patch patches,
but it would be good to have those in a version that might be distributed.

-- 
Glen Overby
Bitnet:  ncoverby@ndsuvax
UUCP: {uunet, ihnp4!umn-cs}!ndsuvax!ncoverby