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