! !Topic: info-vax, entry # 30382 !Date: 18 Apr 90 08:01:15 GMT !From: crash!simpact!jeh@nosc.mil !Subject: Re: Unix-like diff and patch for VMS 01/13 !Message-Id: <1187.262bae4c@dcs.simpact.com> !To: info-vax@kl.sri.com ! ! I've now seen two requests for this within two weeks, and since if one person ! asks for it, many more are probably looking for it but having asked, so it ! seems worthwhile to post it rather than send via email. ! ! Please note that the vms_share file expects to unpack into subdirectories ! [.src] and [.doc] under your current directory (at the time of unpacking), ! and that the build procedures in [.src] expect to write the objects and ! executables into [.bld] (actually [-.bld] relative to the source directory). ! This can, of course, easily be changed to suit your taste. ! ! --- Jamie Hanrahan, Simpact Associates, San Diego CA ! Chair, VMSnet [DECUS uucp] and Internals Working Groups, DECUS VAX Systems SIG ! Internet: jeh@dcs.simpact.com, or if that fails, jeh@crash.cts.com ! Uucp: ...{crash,scubed,decwrl}!simpact!jeh ! $! ------------------ CUT HERE ----------------------- $ v='f$verify(f$trnlnm("SHARE_VERIFY"))' $! $! This archive created by VMS_SHARE Version 7.2-007 22-FEB-1990 $! On 17-APR-1990 23:45:53.67 By user JEH $! $! This VMS_SHARE Written by: $! Andy Harper, Kings College London UK $! $! Acknowledgements to: $! James Gray - Original VMS_SHARE $! Michael Bednarek - Original Concept and implementation $! $!+ THIS PACKAGE DISTRIBUTED IN 13 PARTS, TO KEEP EACH PART $! BELOW 30 BLOCKS $! $! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER $! AND EXECUTE AS A COMMAND PROCEDURE ( @name ) $! $! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING: $! 1. [.DOC]AAAREADME.TXT;1 $! 2. [.DOC]DIFF.DOC;1 $! 3. [.DOC]HOW-TO-DIFF.DOC;1 $! 4. [.DOC]PATCH.DOC;1 $! 5. [.SRC]ARGPROC.C;1 $! 6. [.SRC]BUILD_DIFF.COM;2 $! 7. [.SRC]BUILD_PATCH.COM;2 $! 8. [.SRC]COMMON.H;1 $! 9. [.SRC]CONFIG.H;1 $! 10. [.SRC]DIFF.C;1 $! 11. [.SRC]EXTERN.H;1 $! 12. [.SRC]INCLUDES.H;1 $! 13. [.SRC]INP.C;1 $! 14. [.SRC]INP.H;1 $! 15. [.SRC]INTERN.H;1 $! 16. [.SRC]PATCH.C;1 $! 17. [.SRC]PATCHLEVEL.H;1 $! 18. [.SRC]PCH.C;1 $! 19. [.SRC]PCH.H;1 $! 20. [.SRC]UTIL.C;1 $! 21. [.SRC]UTIL.H;1 $! 22. [.SRC]VERSION.C;1 $! 23. [.SRC]VERSION.H;1 $! $set="set" $set symbol/scope=(nolocal,noglobal) $f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID")) $e="write sys$error ""%UNPACK"", " $w="write sys$output ""%UNPACK"", " $ if f$trnlnm("SHARE_LOG") then $ w = "!" $ ve=f$getsyi("version") $ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START $ e "-E-OLDVER, Must run at least VMS 4.4" $ v=f$verify(v) $ exit 44 $UNPACK: SUBROUTINE ! P1=filename, P2=checksum $ if f$search(P1) .eqs. "" then $ goto file_absent $ e "-W-EXISTS, File ''P1' exists. Skipped." $ delete 'f'* $ exit $file_absent: $ if f$parse(P1) .nes. "" then $ goto dirok $ dn=f$parse(P1,,,"DIRECTORY") $ w "-I-CREDIR, Creating directory ''dn'." $ create/dir 'dn' $ if $status then $ goto dirok $ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped." $ delete 'f'* $ exit $dirok: $ w "-I-PROCESS, Processing file ''P1'." $ if .not. f$verify() then $ define/user sys$output nl: $ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1' PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET( SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:= CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b)); LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION( BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1); IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE; MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1; ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")= 1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF"; POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r); ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1; COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE, "output_file"));ENDPROCEDURE;Unpacker;QUIT; $ delete/nolog 'f'* $ CHECKSUM 'P1' $ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT $ e "-E-CHKSMFAIL, Checksum of ''P1' failed." $ ENDSUBROUTINE $START: $ create 'f' X`09`09`09Patch Kit, Version 2.0 X X`09`09 Copyright (c) 1986, Larry Wall X XYou may copy the patch kit in whole or in part as long as you don't try to Xmake money off it, or pretend that you wrote it. X XNEW FEATURES IN THIS RELEASE X X(Correct) support for 4.3bsd-style context diffs. XFiles can be created from scratch. XYou can specify a fuzz-factor for context matching. XYou can force patch to ask no questions. XYou can specify how much of the leading pathname to strip off filenames. XUses a Configure script for greater portability. XYou are now asked if you want to apply a reversed patch. XNo limit (apart from memory) on the size of hunks. X XFeatures added by Tim Russell (russell@zeus.unl.edu) X XAdded support for VMS from earlier version to patchlevel 9. XAdded parsing support for "patch XArchive-Name: cdiff-v2 X XAfter receiving Bob Larson's sources for the PD context diff program, XI decided to accept his challenge to rewrite the documentation. In Xthe process, I also ported it to TURBOC version 1.5. It probably will Xalso compile in TURBOC 1.0, but since getting the update I dispensed Xwith the previous version and did not try it. `20 X XThe code has been reorganized to strip it of the documentation that Xwas built into it; that has been moved to the file cdiff.mem. Thus, Xthe following shar file includes cdiff.c, cdiff.1 (man source), cdiff.mem X(the previously built-in documentation), cdiff.doc (cdiff.1 passed Xthrough nroff -man for those who do not have nroff available), the Xoriginal README, and a new TC-READ.ME. Follow the notes in TC-READ.ME Xor it will run even slower! `20 X XOf course, no warranties whatsoever go with this. I merely hacked the Xcode minimally. I didn't write it. X--- X XComp.sources.misc: Volume 2, Issue 59 XSubmitted-By: XArchive-Name: pd-cdiff-patch X XNeil Dixon uncovered a flaw in the logic of the cdiff program that Xwas distributed early in January, and which was redistributed with Xchanges to make it compilable in Turbo C. I've tested his patch Xboth on the Unix SysVr2 version and on the PC, and have not found Xany errors. Conversely, the earlier version when compiled in MSC X4.0 (but, for some reason, not when compiled in TC 1.5) would Xsporadically come up with "read" errors. Since it now works in MSC as Xwell as TC, I've included the appropriate ifdefs for both compilers, Xand have incorporated Neil's patch. (This was for clarity. The line Xnumbers in his patch did not correspond precisely to the line numbers Xin the distributed code.) Both the patch as sent to me and the Xrevised code are contained below. X XAs before, I did not write this code. I merely ported it, and of Xcourse make no warranties whatsoever. X X--- X XOk, I guess that I will add my two cents worth. Here is yet another Xrepost of the public domain diff program. `20 X XI have integrated some changes into the i/o portion of the code, providing`2 V0 Xsome significant speedups. These changes were made after spending two`20 Xevenings playging around with the profiler, attempting various fixes to Xmake this beast a little faster. I completed this prior to the latest relea Vse`20 Xof the code (the version listed immediately above). `20 X XI have attempted to merge the changes provided by Mike above, but, since I d Vo`20 Xnot have any other machines close by, I could not test them. X XThe changes which I made are in the following areas: X X`09* modified the fgetss() and fputss() routines. These were the primary X`09 areas of intense activity on the system. From the source that I X`09 could see, these changes should be portable. After timing this`20 X`09 on my 3b1, the changes make this diff run at about the same speed X`09 as the system diff for the files that I was using (amazing isn't it?). X X`09* Moved the defines from within the source code to within the Makefile. X X`09* Ran the code through indent. Sorry about that, but it was the only X`09 way that I could make sure that I got all the other patches integrated` V20 X`09 properly. X X`09* Cleaned up some of the comments and added a few of my own. X X`09* Made a few tweaks to make lint happier. X X`09* Modified the Makefile to allow use of shared libraries. Included X`09 instructions for all the defines in the system as well. X XMark H. Colburn (mark@jhereg.mn.org) X XFixed to support VMS C 3.0 by Tim Russell (russell@zeus.unl.edu). X X12/10/89 mark@infopiz.uucp (uunet!lupine!infopiz!mark) X XFor he VMS environment, the command line interface for diff has been augment Ved Xto be more similar to the native DIFFERENCE utility. Default parts of file Xspecs are taken from the other file name, and allowance is made for diffing Xfile versions by simply specifying a single file/version implying comparison Xwith the previous version. `20 X XExamples: X`20 X `09`09$ diff uucico.c `5B-.v11`5D X`09`09$ diff uucico.c dua0: X`09`09$ diff uucico.c X XNote, the last case properly uses ;-1 as the old file and ;0 as the new. X XFor the VMS environment, Patch has been modified to behave more like a VMS Xutility; it now creates a new version of the patched file leaving the`20 Xoriginal version unmodified. `20 X XOn VMS, if you were patching a file on another device than your default Xlogin device, the patch would seemingly be applied (from the messages),`20 Xbut there would be no changes made and no errors reported. This has Xbeen fixed. X Xdiff has been fixed so that the 'new file name' need not be shorter than`20 Xthe 'old file name'. `20 X XAll patches are now done "in memory" (i.e. Plan A) where before this would`2 V0 Xhave only been the case if the files being patched were STREAM_LF files. XPlan B patches pass through the file several times reading and rereading Xfrom disk. X XAlso, both diff and patch have been given some significant performance`20 Ximprovements by using larger I/O buffers, and both have also been augmented` V20 Xwith argproc, to allow simple command line redirection which these utilities V`20 Xwork quite well with. X X-- Mark Pizzolato $ CALL UNPACK [.DOC]AAAREADME.TXT;1 594373067 $ create 'f' X X X X XDIFF(1) UNIX Programmer's Manual DIFF(1) X X X XNAME X diff - Public Domain diff (context diff) program X XSYNOPSIS X diff `5B -b -c -i -e `5D file1 file2 X XDESCRIPTION X Diff compares two files, showing what must be changed to X make them identical. Either file1 or file2 (but not both) X may refer to directories. If that is the case, a file in the X directory whose name is the same as the other file argument X will be used. The standard input may be used for one of the X files by replacing the argument by "-". Except for the stan- X dard input, both files must be on disk devices. X XOPTIONS X -b Remove trailing whitespace (blanks and tabs) and compress X all other strings of whitespace to a single blank. X X -c Print some context -- matching lines before and after the X non-match section. Mark non-matched sections with "`7C". X X -i Ignore lower/upper case distinctions. X X -e Output is in an "editor script" format which is compati- X ble with the Unix 'ed' editor. X X All information needed to compare the files is maintained in X main memory. This means that very large files (or fairly X large files with many differences) will cause the program to X abort with an "out of space" message. Main memory require- X ments (in words) are approximately: X X 2 * (length of file1 + length of file2) X + 3 * (number of changes) X X (Where "length" is the number of lines of data in each X file.) X X The algorithm reads each file twice, once to build hash X tables and once to check for fortuitous matches (two lines X that are in fact different, but which have the same hash X value). CPU time requirements include sorting the hash X tables and randomly searching memory tables for equivalence X classes. For example, on a time-shared VAX-11/780, comparing X two 1000 line files required about 30 seconds (elapsed clock X time) and about 10,000 bytes of working storage. About 90 X per-cent of the time was taken up by file I/O. X XDIAGNOSTICS X X X X X 4.2 BSD 1 X X X X X X X XDIFF(1) UNIX Programmer's Manual DIFF(1) X X X X Warning, bad option 'x' X The option is ignored. X X Usage ... X Two input files were not specified. X X Can't open input file "filename". X Can't continue. X X Out of space X The program ran out of memory while comparing the two X files. X X Can't read line nnn at xxx in file`5BA/B`5D X This indicates an I/O error when seeking to the X specific line. It should not happen. X X Spurious match, output is not optimal. X Two lines that were different yielded the same hash X value. This is harmless except that the difference X output is not the minimum set of differences between X the two files. For example, instead of the output: X lines 1 to 5 were changed to ... X the program will print X lines 1 to 3 were changed to ... X lines 4 to 5 were changed to ... X X The program uses a CRC16 hash code. X The likelihood of this error is quite small. X XAUTHOR X The diff algorithm was developed by J. W. Hunt and M. D. X McIlroy, using a central algorithm defined by H. S. Stone. X It was published in: X Hunt, J. W., and McIlroy, M. D., X An Algorithm for Differential File Comparison, X Computing Science Technical Report #41, X Bell Laboratories, Murray Hill, NJ 07974 X XBUGS X On RSX and DECUS C on VMS systems, diff may fail if the both +-+-+-+-+-+-+-+- END OF PART 1 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ X files are not "variable-length, implied carriage control" X format. The scopy program can be used to convert files to X this format if problems arise. X X When compiled under VAX C, diff handles STREAM_LF files X properly (in addition to the canonical variable-length X implied carriage control files). Other variations should X work, but have not been tested. X X X X X X 4.2 BSD 2 X X X X X X X XDIFF(1) UNIX Programmer's Manual DIFF(1) X X X X When compiled under VAX C, diff is quite slow for unknown X reasons which ought to be investigated. On the other hand, X it has access to effectively unlimited memory. X X Output in a form suitable for ed - the -e option - seems X rather pointless; the analogue on DEC systems is SLP (SUMSLP X on VMS). It would be simple to provide SLP-compatible out- X put. The question is, why bother - since the various DEC X file comparison utilities already produce it. X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 4.2 BSD 3 X X X $ CALL UNPACK [.DOC]DIFF.DOC;1 404096844 $ create 'f' X How to create a diff X X To create a diff to be sent to Geoff Huston, you use the DIFF program Xwith the "-C" option to create a "context diff" which will have a good chanc Ve Xof working even if someone has made a local change to their source. X X Let's walk through an example. Say I added a nifty change to NEWSPOST.C V. XI want to send it to Geoff to be included in the next patchlevel of NEWS. X X So here's a directory: X X Directory PERM$2:`5BCONSLT32.WORK`5D X X NEWSPOST.C;2 NEWSPOST.C;1 X X Total of 2 files. X X To create the diff, I just use the form "DIFF -C oldfile newfile". One Ximportant thing, though, is to make the newer filename shorter than the olde Vr Xone. I just do this by specifying the version number on the old version, bu Vt Xnot on the new one. X X First, set up a foreign symbol for DIFF if you haven't: X X $ DIFF :== $disk:`5Bdirectory`5DDIFF X X To create the diff: X X $ DEFINE/USER SYS$OUTPUT DIFF.TXT ! Filename of the diff X $ DIFF -C NEWSPOST.C;1 NEWSPOST.C X XHere's what the sample output looks like, in this case: X X--------------------------------------------------------------- X X *** newspost.c;-1 <-- Old filename X --- newspost.c <-- New one, should be shor Vter X ************** <-- Start of first patch X *** 137,142 <-- Section from old file X *msg; X `7B X char mail_cmd`5BIO_SIZE`5D; X `20 X err_line(msg); `20 X if (screen_active) `7B X --- 137,143 ----- <-- Section from new file X *msg; X `7B X char mail_cmd`5BIO_SIZE`5D; X + int added_var; <-- '+' means added line X `20 X err_line(msg); `20 X if (screen_active) `7B X ************** <-- Start of second patch X *** 151,156 X smg$begin_pasteboard_update(&pid); X broad_trap(); X `7D X clear_err_line(); X `7D X #endif X --- 152,158 ----- X smg$begin_pasteboard_update(&pid); X broad_trap(); X `7D X + doit(added_var); <-- Added call to doit() X clear_err_line(); X `7D X #endif X X--------------------------------------------------------------- X XThat's about it. If you have more than one file changed, you can create Xdiffs for each and append them together - patch will do multiple files Xat once. X X Check your patch to make sure it looks right, and it's set to go! X`0C X Applying a patch X X To apply a patch, you must first extract it to a file. You shouldn't Xhave to worry about editing the header from the top, because patch will Xignore it. X X Set up a foreign symbol for patch, i.e. X X $ PATCH :== $disk:`5Bdirectory`5DPATCH X Xthen, set your default directory to wherever the affected files are, Xand invoke PATCH: X X $ PATCH X sets the maximum fuzz factor. This switch only applied X to context diffs, and causes patch to ignore up to that X many lines in looking for places to install a hunk. X Note that a larger fuzz factor increases the odds of a X faulty patch. The default fuzz factor is 2, and it may X not be set to more than the number of lines of context X in the context diff, ordinarily 3. X X -l causes the pattern matching to be done loosely, in case X the tabs and spaces have been munged in your input X file. Any sequence of whitespace in the pattern line X will match any sequence in the input file. Normal X characters must still match exactly. Each line of the X context must still match a line in the input file. X X X X XLOCAL 4.2 BSD 3 X X X X X X X XPATCH(1) UNIX Programmer's Manual PATCH(1) X X X X -n forces patch to interpret the patch file as a normal X diff. X X -N causes patch to ignore patches that it thinks are +-+-+-+-+-+-+-+- END OF PART 2 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+ X reversed or already applied. See also -R . X X -o causes the next argument to be interpreted as the out- X put file name. X X -p X sets the pathname strip count, which controls how path- X names found in the patch file are treated, in case the X you keep your files in a different directory than the X person who sent out the patch. The strip count speci- X fies how many backslashes are to be stripped from the X front of the pathname. (Any intervening directory X names also go away.) For example, supposing the X filename in the patch file was X X /u/howard/src/blurfl/blurfl.c X X setting -p or -p0 gives the entire pathname unmodified, X -p1 gives X X u/howard/src/blurfl/blurfl.c X X without the leading slash, -p4 gives X X blurfl/blurfl.c X X and not specifying -p at all just gives you "blurfl.c". X Whatever you end up with is looked for either in the X current directory, or the directory specified by the -d X switch. X X -r causes the next argument to be interpreted as the X reject file name. X X -R tells patch that this patch was created with the old X and new files swapped. (Yes, I'm afraid that does hap- X pen occasionally, human nature being what it is.) Patch X will attempt to swap each hunk around before applying X it. Rejects will come out in the swapped format. The X -R switch will not work with ed diff scripts because X there is too little information to reconstruct the X reverse operation. X X If the first hunk of a patch fails, patch will reverse X the hunk to see if it can be applied that way. If it X can, you will be asked if you want to have the -R X switch set. If it can't, the patch will continue to be X X X XLOCAL 4.2 BSD 4 X X X X X X X XPATCH(1) UNIX Programmer's Manual PATCH(1) X X X X applied normally. (Note: this method cannot detect a X reversed patch if it is a normal diff and if the first X command is an append (i.e. it should have been a X delete) since appends always succeed, due to the fact X that a null context will match anywhere. Luckily, most X patches add or change lines rather than delete them, so X most reversed normal diffs will begin with a delete, X which will fail, triggering the heuristic.) X X -s makes patch do its work silently, unless an error X occurs. X X -S causes patch to ignore this patch from the patch file, X but continue on looking for the next patch in the file. X Thus X X patch -S + -S + X sets internal debugging flags, and is of interest only X to patch patchers. X XENVIRONMENT X No environment variables are used by patch. X XFILES X /tmp/patch* X XSEE ALSO X diff(1) X XNOTES FOR PATCH SENDERS X There are several things you should bear in mind if you are X going to be sending out patches. First, you can save people X a lot of grief by keeping a patchlevel.h file which is X patched to increment the patch level as the first diff in X the patch file you send out. If you put a Prereq: line in X with the patch, it won't let them apply patches out of order X without some warning. Second, make sure you've specified X the filenames right, either in a context diff header, or X with an Index: line. If you are patching something in a X subdirectory, be sure to tell the patch user to specify a -p X switch as needed. Third, you can create a file by sending X out a diff that compares a null file to the file you want to X create. This will only work if the file you want to create X doesn't exist already in the target directory. Fourth, take X X X XLOCAL 4.2 BSD 5 X X X X X X X XPATCH(1) UNIX Programmer's Manual PATCH(1) X X X X care not to send out reversed patches, since it makes people X wonder whether they already applied the patch. Fifth, while X you may be able to get away with putting 582 diff listings X into one file, it is probably wiser to group related patches X into separate files in case something goes haywire. X XDIAGNOSTICS X Too many to list here, but generally indicative that patch X couldn't parse your patch file. X X The message "Hmm..." indicates that there is unprocessed X text in the patch file and that patch is attempting to X intuit whether there is a patch in that text and, if so, X what kind of patch it is. X XCAVEATS X Patch cannot tell if the line numbers are off in an ed X script, and can only detect bad line numbers in a normal X diff when it finds a "change" or a "delete" command. A con- X text diff using fuzz factor 3 may have the same problem. X Until a suitable interactive interface is added, you should X probably do a context diff in these cases to see if the X changes made sense. Of course, compiling without errors is X a pretty good indication that the patch worked, but not X always. X X Patch usually produces the correct results, even when it has X to do a lot of guessing. However, the results are X guaranteed to be correct only when the patch is applied to X exactly the same version of the file that the patch was gen- X erated from. X XBUGS X Could be smarter about partial matches, excessively deviant X offsets and swapped code, but that would take an extra pass. X X If code has been duplicated (for instance with #ifdef OLD- X CODE ... #else ... #endif), patch is incapable of patching X both versions, and, if it works at all, will likely patch X the wrong one, and tell you that it succeeded to boot. X X If you apply a patch you've already applied, patch will X think it is a reversed patch, and offer to un-apply the X patch. This could be construed as a feature. X X X X X X X X X X XLOCAL 4.2 BSD 6 X X X $ CALL UNPACK [.DOC]PATCH.DOC;1 964225761 $ create 'f' X/* X * @(#)argproc.c 1.0 89/02/01`09`09Mark Pizzolato (mark@infopiz.uucp)`09 X */ X X#ifndef lint Xchar argproc_version`5B`5D = "@(#)argproc.c VMS uucp Version infopiz-1.0"; X#endif X X#include "includes.h"`09`09/* System include files, system dependent */ X X`0C X/* X * getredirection() is intended to aid in porting C programs X * to VMS (Vax-11 C) which does not support '>' and '<' X * I/O redirection, along with a command line pipe mechanism X * using the '`7C' AND background command execution '&'. X * The piping mechanism will probably work with almost any 'filter' type X * of program. With suitable modification, it may useful for other X * portability problems as well. X * X * Author: Mark Pizzolato`09mark@infopiz.UUCP X */ Xstruct list_item X `7B X struct list_item *next; X char *value; X `7D; X Xint Xgetredirection(ac, av) Xint`09`09*ac; Xchar`09`09***av; X/* X * Process vms redirection arg's. Exit if any error is seen. X * If getredirection() processes an argument, it is erased X * from the vector. getredirection() returns a new argc and argv value. X * In the event that a background command is requested (by a trailing "&"), X * this routine creates a background subprocess, and simply exits the progra Vm. X * X * Warning: do not try to simplify the code for vms. The code X * presupposes that getredirection() is called before any data is X * read from stdin or written to stdout. X * X * Normal usage is as follows: X * X *`09main(argc, argv) X *`09int`09`09argc; X * `09char`09`09*argv`5B`5D; X *`09`7B X *`09`09getredirection(&argc, &argv); X *`09`7D X */ X`7B X int`09`09`09argc = *ac;`09/* Argument Count`09 */ X char`09`09**argv = *av;`09/* Argument Vector`09 */ X char`09`09*ap; `09`09/* Argument pointer`09 */ X int`09 `09`09j;`09`09/* argv`5B`5D index`09`09 */ X extern int`09`09errno;`09`09/* Last vms i/o error `09 */ X int`09`09`09item_count = 0;`09/* Count of Items in List */ X struct list_item `09*list_head = 0;`09/* First Item in List`09 */ X struct list_item`09*list_tail;`09/* Last Item in List`09 */ X char `09`09*in = NULL;`09/* Input File Name`09 */ X char `09`09*out = NULL;`09/* Output File Name`09 */ X char `09`09*outmode = "w";`09/* Mode to Open Output File */ X int`09`09`09cmargc = 0; `09/* Piped Command Arg Count */ X char`09`09**cmargv = NULL;/* Piped Command Arg Vector */ X X /* X * First handle the case where the last thing on the line ends with X * a '&'. This indicates the desire for the command to be run in a X * subprocess, so we satisfy that desire. X */ X ap = argv`5Bargc-1`5D; X if (0 == strcmp("&", ap)) X`09exit(background_process(--argc, argv)); X if ('&' == ap`5Bstrlen(ap)-1`5D) X`09`7B X`09ap`5Bstrlen(ap)-1`5D = '\0'; X`09exit(background_process(argc, argv)); X`09`7D X /* X * Now we handle the general redirection cases that involve '>', '>>', X * '<', and pipes '`7C'. X */ X for (j = 0; j < argc; ++j) X`09`7B X`09if (0 == strcmp("<", argv`5Bj`5D)) X`09 `7B X`09 if (j+1 >= argc) X`09`09`7B X`09`09errno = EINVAL; X`09`09perror("No input file"); X`09`09exit(EXIT_ERR); X`09`09`7D X`09 in = argv`5B++j`5D; X`09 continue; X`09 `7D X`09if ('<' == *(ap = argv`5Bj`5D)) X`09 `7B X`09 in = 1 + ap; X`09 continue; X`09 `7D X`09if (0 == strcmp(">", ap)) X`09 `7B X`09 if (j+1 >= argc) X`09`09`7B X`09`09errno = EINVAL; X`09`09perror("No output file"); X`09`09exit(EXIT_ERR); X`09`09`7D X`09 out = argv`5B++j`5D; X`09 continue; X`09 `7D X`09if ('>' == *ap) X`09 `7B X`09 if ('>' == ap`5B1`5D) X`09`09`7B X`09`09outmode = "a"; X`09`09if ('\0' == ap`5B2`5D) X`09`09 out = argv`5B++j`5D; X`09`09else X`09`09 out = 2 + ap; X`09`09`7D X`09 else X`09`09out = 1 + ap; X`09 continue; X`09 `7D X`09if (0 == strcmp("`7C", argv`5Bj`5D)) X`09 `7B X`09 if (j+1 >= argc) X`09`09`7B X`09`09errno = EPIPE; X`09`09perror("No command to Pipe to"); X`09`09exit(EXIT_ERR); X`09`09`7D X`09 cmargc = argc-(j+1); X`09 cmargv = &argv`5Bj+1`5D; X`09 argc = j; X`09 continue; X`09 `7D X`09if ('`7C' == *(ap = argv`5Bj`5D)) X`09 `7B X`09 ++argv`5Bj`5D; X`09 cmargc = argc-j; X`09 cmargv = &argv`5Bj`5D; X`09 argc = j; X`09 continue; X`09 `7D X`09expand_wild_cards(ap, &list_head, &list_tail, &item_count); X`09`7D X /* X * Allocate and fill in the new argument vector, Some Unix's terminate X * the list with an extra null pointer. X */ X argv = *av = calloc(item_count+1, sizeof(char *)); X for (j = 0; j < item_count; ++j, list_head = list_head->next) X`09argv`5Bj`5D = list_head->value; X *ac = item_count; X if (cmargv != NULL) X`09`7B X`09char subcmd`5B1024`5D; X`09static char *pipe_and_fork(); X X`09if (out != NULL) X`09 `7B X`09 errno = EINVAL; X`09 perror("Invalid '`7C' and '>' specified"); X`09 exit(EXIT_ERR); X`09 `7D X`09strcpy(subcmd, cmargv`5B0`5D); X`09for (j = 1; j < cmargc; ++j) X`09 `7B X`09 strcat(subcmd, " \""); X`09 strcat(subcmd, cmargv`5Bj`5D); X`09 strcat(subcmd, "\""); X`09 `7D X`09out = pipe_and_fork(subcmd); X`09`7D X if ((in != NULL) && (NULL == freopen(in, "r", stdin, "mbc=32", "mbf=2")) V) X`09`7B X`09perror(in); `09 `09/* Can't find file`09`09*/ X`09exit(EXIT_ERR);`09`09/* Is a fatal error`09`09*/ X`09`7D X if ((out != NULL) && (NULL == freopen(out, outmode, stdout, "mbc=32", "m Vbf=2"))) X`09`7B`09 X`09perror(ap);`09`09/* Error, can't write or append`09*/ X`09exit(EXIT_ERR);`09`09/* Is a fatal error`09`09*/ X`09`7D X#ifdef DEBUG X fprintf(stderr, "Arglist:\n"); X for (j = 0; j < *ac; ++j) X`09fprintf(stderr, "argv`5B%d`5D = '%s'\n", j, argv`5Bj`5D); X#endif X`7D X Xstatic add_item(head, tail, value, count) Xstruct list_item **head; Xstruct list_item **tail; Xchar *value; Xint *count; X`7B X if (*head == 0) X`09`7B X`09if (NULL == (*head = calloc(1, sizeof(**head)))) X`09 `7B X`09 errno = ENOMEM; X`09 perror(""); X`09 exit(EXIT_ERR); X`09 `7D X`09*tail = *head; X`09`7D X else X`09if (NULL == ((*tail)->next = calloc(1, sizeof(**head)))) X`09 `7B X`09 errno = ENOMEM; X`09 perror(""); X`09 exit(EXIT_ERR); X`09 `7D X`09else X`09 *tail = (*tail)->next; X (*tail)->value = value; X ++(*count); X`7D X Xstatic expand_wild_cards(item, head, tail, count) Xchar *item; Xstruct ltem_list **head; Xstruct ltem_list **tail; Xint *count; X`7B Xint expcount = 0; Xint context = 0; Xint status; Xint status_value; Xint had_version; X$DESCRIPTOR(filespec, item); X$DESCRIPTOR(defaultspec, "SYS$DISK:`5B`5D*.*;"); X$DESCRIPTOR(resultspec, ""); X X if (strcspn(item, "*%") == strlen(item)) X`09`7B X`09add_item(head, tail, item, count); X`09return; X`09`7D X resultspec.dsc$b_dtype = DSC$K_DTYPE_T; X resultspec.dsc$b_class = DSC$K_CLASS_D; X resultspec.dsc$a_pointer = NULL; X filespec.dsc$w_length = strlen(item); X /* X * Only return version specs, if the caller specified a version X */ X had_version = strchr(item, ';'); X while (1 == (1&lib$find_file(&filespec, &resultspec, &context, X `09`09`09`09 &defaultspec, 0, &status_value, &0))) X`09`7B X`09char *string; X`09char *c; X X`09if (NULL == (string = calloc(1, resultspec.dsc$w_length+1))) X`09 `7B X`09 errno = ENOMEM; X`09 perror(""); X`09 exit(EXIT_ERR); X`09 `7D X`09strncpy(string, resultspec.dsc$a_pointer, resultspec.dsc$w_length); X`09string`5Bresultspec.dsc$w_length`5D = '\0'; X`09if (NULL == had_version) X`09 *((char *)strrchr(string, ';')) = '\0'; X`09/* +-+-+-+-+-+-+-+- END OF PART 3 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 4 -+-+-+-+-+-+-+-+ X`09 * Be consistent with what the C RTL has already done to the rest of X`09 * the argv items and lowercase all of these names. X`09 */ X`09for (c = string; *c; ++c) X`09 if (isupper(*c)) X`09`09*c = tolower(*c); X`09add_item(head, tail, string, count); X`09++expcount; X`09`7D X if (expcount == 0) X`09add_item(head, tail, item, count); X lib$sfree1_dd(&resultspec); X lib$find_file_end(&context); X`7D X Xstatic int child_st`5B2`5D;`09/* Event Flag set when child process completes V`09*/ X Xstatic short child_chan;/* I/O Channel for Pipe Mailbox`09`09`09*/ X Xstatic exit_handler(status) Xint *status; X`7B Xshort iosb`5B4`5D; X X if (0 == child_st`5B0`5D) X`09`7B X#ifdef DEBUG X`09fprintf(stderr, "Waiting for Child Process to Finnish . . .\n"); X#endif X`09sys$qiow(0, child_chan, IO$_WRITEOF, iosb, 0, 0, 0, 0, 0, 0, 0, 0); X`09sys$dassgn(child_chan); X`09fclose(stdout); X`09sys$synch(0, child_st); X`09`7D X`7D X X#include syidef`09`09/* System Information Definitions`09*/ X Xstatic sig_child(chan) Xint chan; X`7B X#ifdef DEBUG X fprintf(stderr, "Child Completion AST\n"); X#endif X if (child_st`5B0`5D == 0) X`09child_st`5B0`5D = 1; X`7D X Xstatic struct exit_control_block X `7B X struct exit_control_block *flink; X int`09(*exit_routine)(); X int arg_count; X int *status_address; X int exit_status; X `7D exit_block = X `7B X 0, X exit_handler, X 1, X &exit_block.exit_status, X 0 X `7D; X Xstatic char *pipe_and_fork(cmd) Xchar *cmd; X`7B X $DESCRIPTOR(cmddsc, cmd); X static char mbxname`5B64`5D; X $DESCRIPTOR(mbxdsc, mbxname); X short iosb`5B4`5D; X int status; X int pid; X struct X`09`7B X`09short dna_buflen; X`09short dna_itmcod; X`09char *dna_buffer; X`09short *dna_retlen; X`09int listend; X`09`7D itmlst = X`09`7B X`09sizeof(mbxname), X`09DVI$_DEVNAM, X`09mbxname, X`09&mbxdsc.dsc$w_length, X`090 X`09`7D; X int mbxsize; X struct X`09`7B X`09short mbf_buflen; X`09short mbf_itmcod; X`09int *mbf_maxbuf; X`09short *mbf_retlen; X`09int listend; X`09`7D syiitmlst = X`09`7B X`09sizeof(mbxsize), X`09SYI$_MAXBUF, X`09&mbxsize, X`090, X`090 X`09`7D; X X cmddsc.dsc$w_length = strlen(cmd); X /* X * Get the SYSGEN parameter MAXBUF, and the smaller of it and 2048 as X * the size of the 'pipe' mailbox. X */ X if (1 == (1&(vaxc$errno = sys$getsyiw(0, 0, 0, &syiitmlst, iosb, 0, 0, 0 V)))) X`09vaxc$errno = iosb`5B0`5D; X if (0 == (1&vaxc$errno)) X`09`7B X `09errno = EVMSERR; X`09perror("Can't get SYSGEN parameter value for MAXBUF"); X`09exit(EXIT_ERR); X`09`7D X if (mbxsize > 2048) X`09mbxsize = 2048; X if (0 == (1&(vaxc$errno = sys$crembx(0, &child_chan, mbxsize, mbxsize, 0 V, 0, 0)))) X`09`7B X`09errno = EVMSERR; X`09perror("Can't create pipe mailbox"); X`09exit(EXIT_ERR); X`09`7D X if (1 == (1&(vaxc$errno = sys$getdviw(0, child_chan, 0, &itmlst, iosb, X `09`09`09`09`09 0, 0, 0)))) X`09vaxc$errno = iosb`5B0`5D; X if (0 == (1&vaxc$errno)) X`09`7B X `09errno = EVMSERR; X`09perror("Can't get pipe mailbox device name"); X`09exit(EXIT_ERR); X`09`7D X mbxname`5Bmbxdsc.dsc$w_length`5D = '\0'; X#ifdef DEBUG X fprintf(stderr, "Pipe Mailbox Name = '%s'\n", mbxname); X#endif X if (0 == (1&(vaxc$errno = lib$spawn(&cmddsc, &mbxdsc, 0, &1, X `09`09`09`09`090, &pid, child_st, &0, sig_child, X `09`09`09`09`09&child_chan)))) X`09`7B X`09errno = EVMSERR; X`09perror("Can't spawn subprocess"); X`09exit(EXIT_ERR); X`09`7D X#ifdef DEBUG X fprintf(stderr, "Subprocess's Pid = %08X\n", pid); X#endif X sys$dclexh(&exit_block); X return(mbxname); X`7D X Xbackground_process(argc, argv) Xint argc; Xchar **argv; X`7B Xchar command`5B2048`5D = "$"; X$DESCRIPTOR(value, command); X$DESCRIPTOR(cmd, "BACKGROUND$COMMAND"); X$DESCRIPTOR(null, "NLA0:"); Xint pid; X X strcat(command, argv`5B0`5D); X while (--argc) X`09`7B X`09strcat(command, " \""); X`09strcat(command, *(++argv)); X`09strcat(command, "\""); X`09`7D X value.dsc$w_length = strlen(command); X if (0 == (1&(vaxc$errno = lib$set_symbol(&cmd, &value)))) X`09`7B X`09errno = EVMSERR; X`09perror("Can't create symbol for subprocess command"); X`09exit(EXIT_ERR); X`09`7D X if (0 == (1&(vaxc$errno = lib$spawn(&cmd, &null, 0, &17, 0, &pid)))) X`09`7B X`09errno = EVMSERR; X`09perror("Can't spawn subprocess"); X`09exit(EXIT_ERR); X`09`7D X#ifdef DEBUG X fprintf(stderr, "%s\n", command); X#endif X fprintf(stderr, "%08X\n", pid); X return(EXIT_OK); X`7D X`0C X/* got this off net.sources */ X X#ifdef`09VMS X#define`09index`09strchr X#endif`09/*VMS*/ X X/* X * get option letter from argument vector X */ Xint`09opterr = 1,`09`09/* useless, never set or used */ X`09optind = 1,`09`09/* index into parent argv vector */ X`09optopt;`09`09`09/* character checked for validity */ Xchar`09*optarg;`09`09/* argument associated with option */ X X#define BADCH`09(int)'?' X#define EMSG`09"" X#define tell(s)`09fputs(*nargv,stderr);fputs(s,stderr); \ X`09`09fputc(optopt,stderr);fputc('\n',stderr);return(BADCH); X Xgetopt(nargc,nargv,ostr) Xint`09nargc; Xchar`09**nargv, X`09*ostr; X`7B X`09static char`09*place = EMSG;`09/* option letter processing */ X`09register char`09*oli;`09`09/* option letter list index */ X`09char`09*index(); X X`09if(!*place) `7B`09`09`09/* update scanning pointer */ X`09`09if(optind >= nargc `7C`7C *(place = nargv`5Boptind`5D) != '-' `7C`7C ! V*++place) return(EOF); X`09`09if (*place == '-') `7B`09/* found "--" */ X`09`09`09++optind; X`09`09`09return(EOF); X`09`09`7D X`09`7D`09`09`09`09/* option letter okay? */ X`09if ((optopt = (int)*place++) == (int)':' `7C`7C !(oli = index(ostr,optopt V))) `7B X`09`09if(!*place) ++optind; X`09`09tell(": illegal option -- "); X`09`7D X`09if (*++oli != ':') `7B`09`09/* don't need argument */ X`09`09optarg = NULL; X`09`09if (!*place) ++optind; X`09`7D X`09else `7B`09`09`09`09/* need an argument */ X`09`09if (*place) optarg = place;`09/* no white space */ X`09`09else if (nargc <= ++optind) `7B`09/* no arg */ X`09`09`09place = EMSG; X`09`09`09tell(": option requires an argument -- "); X`09`09`7D X`09 `09else optarg = nargv`5Boptind`5D;`09/* white space */ X`09`09place = EMSG; X`09`09++optind; X`09`7D X`09return(optopt);`09`09`09/* dump back option letter */ X`7D $ CALL UNPACK [.SRC]ARGPROC.C;1 303622112 $ create 'f' X$ cc/object=`5B-.bld`5D diff X$ cc/object=`5B-.bld`5D argproc X$ link/notrace/exec=`5B-.bld`5D `5B-.bld`5Ddiff,`5B-.bld`5Dargproc,sys$input V:/opt Xsys$share:vaxcrtl.exe/share $ CALL UNPACK [.SRC]BUILD_DIFF.COM;2 2081124049 $ create 'f' X$ on error then goto oops X$ cc /obj=`5B-.bld`5D patch X$ cc /obj=`5B-.bld`5D inp X$ cc /obj=`5B-.bld`5D util X$ cc /obj=`5B-.bld`5D version X$ cc /obj=`5B-.bld`5D pch X$ cc /obj=`5B-.bld`5D argproc X$! X$ link/notrace/exec=`5B-.bld`5D - X`5B-.bld`5Dpatch,`5B-.bld`5Dinp,`5B-.bld`5Dutil,`5B-.bld`5Dversion,`5B-.bld` V5Dpch,- X`5B-.bld`5Dargproc,sys$input:/opt Xsys$share:vaxcrtl.exe/share X$ write sys$output "Patch built successfully." X$ exit X$! X$ oops: X$ write sys$output "Errors in build." $ CALL UNPACK [.SRC]BUILD_PATCH.COM;2 789537813 $ create 'f' X/* $Header: common.h,v 2.0 86/09/17 15:36:39 lwall Exp $ X * X * $Log:`09common.h,v $ X * Revision 2.0 86/09/17 15:36:39 lwall X * Baseline for netwide release. X *`20 X */ X X#define DEBUGGING X X#include "config.h" X X/* shut lint up about the following when return value ignored */ X X#define Signal (void)signal X#ifdef VMS X#define Unlink (void)delete X#define unlink delete X#else X#define Unlink (void)unlink X#endif X#define Lseek (void)lseek X#define Fseek (void)fseek X#define Fstat (void)fstat X#define Pclose (void)pclose X#define Close (void)close X#define Fclose (void)fclose X#define Fflush (void)fflush X#define Sprintf (void)sprintf X#define Mktemp (void)mktemp X#define Strcpy (void)strcpy X#define Strcat (void)strcat X X#ifdef VMS X#include ctype X#include signal X#include stdio X#include assert X#include types X#include stat X#else X#include X#include X#include X#include X#include X#include X#endif X X/* constants */ X X#define TRUE (1) X#define FALSE (0) X X#define MAXHUNKSIZE 100000`09`09/* is this enough lines? */ X#define INITHUNKMAX 125`09`09`09/* initial dynamic allocation size */ X#define MAXLINELEN 1024 X#define BUFFERSIZE 1024 X#define ORIGEXT ".orig" X#define SCCSPREFIX "s." X#define GET "get -e %s" X#define RCSSUFFIX ",v" X#define CHECKOUT "co -l %s" X X/* handy definitions */ X X#define Null(t) ((t)0) X#define Nullch Null(char *) X#define Nullfp Null(FILE *) X#define Nulline Null(LINENUM) X X#define Ctl(ch) ((ch) & 037) X X#define strNE(s1,s2) (strcmp(s1, s2)) X#define strEQ(s1,s2) (!strcmp(s1, s2)) X#define strnNE(s1,s2,l) (strncmp(s1, s2, l)) X#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l)) X X/* typedefs */ X Xtypedef char bool; Xtypedef long LINENUM;`09`09`09/* must be signed */ Xtypedef unsigned MEM;`09`09`09/* what to feed malloc */ X X/* globals */ X XEXT int Argc;`09`09`09`09/* guess */ XEXT char **Argv; XEXT int Argc_last;`09`09`09/* for restarting plan_b */ XEXT char **Argv_last; X XEXT struct stat filestat;`09`09/* file statistics area */ XEXT int filemode INIT(0644); X XEXT char buf`5BMAXLINELEN`5D;`09`09/* general purpose buffer */ XEXT FILE *ofp INIT(Nullfp);`09`09/* output file pointer */ XEXT FILE *rejfp INIT(Nullfp);`09`09/* reject file pointer */ X XEXT bool using_plan_a INIT(TRUE);`09/* try to keep everything in memory */ XEXT bool out_of_mem INIT(FALSE);`09/* ran out of memory in plan a */ X X#define MAXFILEC 2 XEXT int filec INIT(0);`09`09`09/* how many file arguments? */ XEXT char *filearg`5BMAXFILEC`5D; XEXT bool ok_to_create_file INIT(FALSE); XEXT char *bestguess INIT(Nullch);`09/* guess at correct filename */ X XEXT char *outname INIT(Nullch); XEXT char rejname`5B128`5D; X XEXT char *origext INIT(Nullch); X X#ifdef VMS Xchar TMPOUTNAME`5B`5D = "sys$scratch:patchoXXXXXX"; Xchar TMPINNAME`5B`5D = "sys$scratch:patchiXXXXXX"; Xchar TMPREJNAME`5B`5D = "sys$scratch:patchrXXXXXX"; Xchar TMPPATNAME`5B`5D = "sys$scratch:patchpXXXXXX"; X#else XEXT char TMPOUTNAME`5B`5D INIT("/tmp/patchoXXXXXX"); XEXT char TMPINNAME`5B`5D INIT("/tmp/patchiXXXXXX");`09/* might want /usr/tmp V here */ XEXT char TMPREJNAME`5B`5D INIT("/tmp/patchrXXXXXX"); XEXT char TMPPATNAME`5B`5D INIT("/tmp/patchpXXXXXX"); X#endif X XEXT bool toutkeep INIT(FALSE); XEXT bool trejkeep INIT(FALSE); X XEXT LINENUM last_offset INIT(0); X#ifdef DEBUGGING XEXT int debug INIT(0); X#endif XEXT LINENUM maxfuzz INIT(2); XEXT bool force INIT(FALSE); XEXT bool verbose INIT(TRUE); XEXT bool reverse INIT(FALSE); XEXT bool noreverse INIT(FALSE); XEXT bool skip_rest_of_patch INIT(FALSE); XEXT int strippath INIT(957); XEXT bool canonicalize INIT(FALSE); X X#define CONTEXT_DIFF 1 X#define NORMAL_DIFF 2 X#define ED_DIFF 3 X#define NEW_CONTEXT_DIFF 4 XEXT int diff_type INIT(0); X XEXT bool do_defines INIT(FALSE);`09/* patch using ifdef, ifndef, etc. */ XEXT char if_defined`5B128`5D;`09`09/* #ifdef xyzzy */ XEXT char not_defined`5B128`5D;`09`09/* #ifndef xyzzy */ XEXT char else_defined`5B`5D INIT("#else\n");/* #else */ XEXT char end_defined`5B128`5D;`09`09/* #endif xyzzy */ X XEXT char *revision INIT(Nullch);`09/* prerequisite revision, if any */ X Xchar *malloc(); Xchar *realloc(); Xchar *strcpy(); Xchar *strcat(); Xlong atol(); Xlong lseek(); Xchar *mktemp(); $ CALL UNPACK [.SRC]COMMON.H;1 1450187579 $ create 'f' X/* config.h X * This file was produced by running the Configure script. X * Feel free to modify any of this as the need arises. X */ X X X#define`09`09EUNICE`09`09/* no file linking? */ X#define`09`09VMS`09`09/* other assorted ickies? */ X X#define`09`09index strchr`09/* cultural */ X#define`09`09rindex strrchr`09/* differences? */ X X#/*undef`09void int`09/* is void to be avoided? */ X X/* How many register declarations are paid attention to? */ X X#define Reg1 register`09`09/**/ X#define Reg2 register`09`09/**/ X#define Reg3 register`09`09/**/ X#define Reg4 register`09`09/**/ X#define Reg5 register`09`09/**/ X#define Reg6 register`09`09/**/ X#define Reg7 `09`09/**/ X#define Reg8 `09`09/**/ X#define Reg9 `09`09/**/ X#define Reg10 `09`09/**/ X#define Reg11 `09`09/**/ X#define Reg12 `09`09/**/ X#define Reg13 `09`09/**/ X#define Reg14 `09`09/**/ X#define Reg15 `09`09/**/ X#define Reg16 `09`09/**/ X $ CALL UNPACK [.SRC]CONFIG.H;1 688866093 $ create 'f' X/* X * diff.c - public domain context diff program X * X * This is pd-diff from comp.sources.misc. X */ X X#ifdef TURBO X#include X#include X#include X#include X#include X#include X X#else `20 X X#ifdef VMS X X#include ssdef X#include stsdef X#include stdio X#include ctype X#define IO_SUCCESS -1 X#define IO_ERROR 1 X X#else X X#include X#include X X#endif /* vms */ X X#endif /* TURBO */ X X#define EOS `090 X#ifdef unix Xchar temfile`5BL_tmpnam`5D; Xchar *tmpnam(); X#define TEMPFILE (temfile`5B0`5D? temfile: (tmpnam(temfile), temfile)) X#else /* unix */ X#define TEMPFILE "diff.tmp" X#endif /* unix */ X#define TRUE `091 X#define FALSE `090 X X#ifdef pdp11 X#define short int X#endif /* pdp11 */ X Xtypedef struct candidate `7B X`09int b;`09`09`09/* Line in fileB `09 */ X`09int a;`09`09`09/* Line in fileA `09 */ X`09int link;`09`09/* Previous candidate `09 */ X`7D CANDIDATE; X Xtypedef struct line `7B X`09unsigned short hash;`09`09/* Hash value etc. `09 */ X`09short serial;`09`09/* Line number `09 */ X`7D LINE; X XLINE *file`5B2`5D;`09`09/* Hash/line for total file */ X#define fileA file`5B0`5D X#define fileB file`5B1`5D X XLINE *sfile`5B2`5D;`09`09/* Hash/line after prefix */ X#define sfileA sfile`5B0`5D X#define sfileB sfile`5B1`5D X Xint len`5B2`5D;`09`09`09/* Actual lines in each file */ X#define lenA len`5B0`5D X#define lenB len`5B1`5D X +-+-+-+-+-+-+-+- END OF PART 4 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 5 -+-+-+-+-+-+-+-+ Xint slen`5B2`5D;`09`09/* Squished lengths `09 */ X#define slenA slen`5B0`5D X#define slenB slen`5B1`5D X Xint prefix;`09`09`09/* Identical lines at start */ Xint suffix;`09`09`09/* Identical lenes at end */ X XFILE *infd`5B2`5D = `7BNULL, NULL`7D;`09/* Input file identifiers V */ XFILE *tempfd;`09`09`09/* Temp for input redirection */ X Xextern long ftell(); Xextern FILE *fopen(); X X#ifdef TURBO Xextern void *malloc(); X#else /* !TURBO */ Xextern char *malloc(); X#endif /* TURBO */ X Xchar *fgetss(); Xunsigned short hash(); X X#ifdef`09AMIGA X/* Define these types for Amiga C */ Xchar *savptr; Xint savsiz; Xchar *wrk; Xchar *wrk2; Xint cpysiz; X#endif /* AMIGA */ X X/* X * The following vectors overlay the area defined by fileA X */ X Xshort *class;`09`09`09/* Unsorted line numbers */ Xint *klist;`09`09`09/* Index of element in clist */ XCANDIDATE *clist;`09`09`09/* Storage pool for candidates */ Xint clength = 0;`09/* Number of active candidates */ X#define`09CSIZE_INC 50`09`09`09/* How many to allocate each time we have to V */ Xint csize = CSIZE_INC;`09`09/* Current size of storage pool */ X Xint *match;`09`09`09/* Longest subsequence `09 */ Xlong *oldseek;`09`09/* Seek position in file A */ X X/* X * The following vectors overlay the area defined by fileB X */ X Xshort *member;`09`09`09/* Concatenated equiv. classes */ Xlong *newseek;`09`09/* Seek position in file B */ Xchar *textb;`09`09`09/* Input from file2 for check */ X X/* X * Global variables X */ X Xint eflag = FALSE;`09/* Edit script requested */ Xint bflag = FALSE;`09/* Blank supress requested */ Xint cflag = FALSE;`09/* Context printout `09 */ Xint iflag = FALSE;`09/* Ignore case requested */ Xchar text`5B257`5D;`09`09/* Input line from file1 */ Xextern char *myalloc();`09`09/* Storage allocator `09 */ X Xextern char *compact();`09`09/* Storage compactor `09 */ X X#ifdef DEBUG X#ifndef OSK X#define TIMING X#endif /* OSK */ X#endif /* DEBUG */ X#ifdef TIMING Xextern long time(); Xextern char *4532mend; Xlong totaltime; Xlong sectiontime; Xchar *mstart; X#endif /* TIMING */ Xvoid`09`09`09free(); Xvoid`09`09`09exit(); X#ifndef OSK Xvoid`09`09`09perror(); X#endif /* OSK */ X X/* X * Diff main program X */ X Xmain(argc, argv) X`09int argc; X`09char **argv; X`7B X`09register int i; X`09register char *ap; X X#ifdef OSK X`09extern int _memmins; X`09_memmins = 16 * 1024;`09`09/* tell OSK we will malloc a lot */ X#endif /* OSK */ X#ifdef TIMING X`09sectiontime = time(&totaltime); X#endif /* TIMING */ X X#ifdef VMS X`09getredirection(&argc, &argv); X#endif X`09while (argc > 1 && *(ap = argv`5B1`5D) == '-' && *++ap != EOS) `7B X`09`09while (*ap != EOS) `7B X`09`09`09switch ((*ap++)) `7B X`09`09`09case 'b': X`09`09`09`09bflag++; X`09`09`09`09break; X X`09`09`09case 'c': X`09`09`09`09if (*ap > '0' && *ap <= '9') X`09`09`09`09`09cflag = *ap++ - '0'; X`09`09`09`09else X`09`09`09`09`09cflag = 3; X`09`09`09`09break; X X`09`09`09case 'e': X`09`09`09`09eflag++; X`09`09`09`09break; X X`09`09`09case 'i': X`09`09`09`09iflag++; X`09`09`09`09break; X X`09`09`09default: X`09`09`09`09fprintf(stderr, X`09`09`09`09`09`09"Warning, bad option '%c'\n", X`09`09`09`09`09`09ap`5B-1`5D); X`09`09`09`09break; X`09`09`09`7D X`09`09`7D X`09`09argc--; X`09`09argv++; X`09`7D X X#ifdef VMS X`09/* For VMS, we allow comparison of a particular version of a file X`09 AND the version immediately preeceding it. This is implied by X`09 simply mentioning the single file name. */ X`09if (argc == 2) `7B X`09`09if (argv`5B0`5D = previous_version(argv`5B1`5D)) `7B X`09`09`09--argv; X`09`09`09++argc; X`09`09`7D X`09`7D X#endif X`09if (argc != 3) X`09`09error("Usage: diff `5B-options`5D file1 file2"); X`09if (cflag && eflag) `7B X`09`09fprintf(stderr, X`09`09`09`09"Warning, -c and -e are incompatible, -c supressed.\n"); X`09`09cflag = FALSE; X`09`7D X`09argv++; X`09for (i = 0; i <= 1; i++) `7B X`09`09if (argv`5Bi`5D`5B0`5D == '-' && argv`5Bi`5D`5B1`5D == EOS) `7B X`09`09`09infd`5Bi`5D = stdin; X`09`09`09if ((tempfd = fopen(TEMPFILE, "w")) == NULL) X`09`09`09`09cant(TEMPFILE, "work", 1); X`09`09`7D else `7B X`09`09`09infd`5Bi`5D = fopen(argv`5Bi`5D, "r" X#ifdef VMS X`09`09`09`09`09`09 , "mbc=64", "mbf=2" X#endif X`09`09`09`09`09`09`09); X`09`09`7D X`09`7D X X`09if (infd`5B0`5D == stdin && infd`5B1`5D == stdin) X`09`09error("Can't diff two things both on standard input."); X X`09if (infd`5B0`5D == NULL && infd`5B1`5D == NULL) `7B X`09`09cant(argv`5B0`5D, "input", 0); X`09`09cant(argv`5B1`5D, "input", 1); X`09`7D X#ifdef VMS X`09if (infd`5B1`5D == NULL) X`09`09opendir(1, &argv`5B1`5D, infd`5B0`5D); X`09else if (infd`5B0`5D == NULL) X`09`09opendir(0, &argv`5B0`5D, infd`5B1`5D); X#endif /* vms */ X`09for (i = 0; i <= 1; i++) X`09`09if (!infd`5Bi`5D) X`09`09`09cant(argv`5Bi`5D, "input", 2);`09`09/* Fatal error */ X X`09/* X`09 * Read input, building hash tables.`20 X`09 */ X`09input(0); X`09input(1); X`09squish(); X#ifdef DEBUG X`09printf("before sort\n"); X`09for (i = 1; i <= slenA; i++) X`09`09printf("sfileA`5B%d`5D = %6d %06o\n", X`09`09`09 i, sfileA`5Bi`5D.serial, sfileA`5Bi`5D.hash); X`09for (i = 1; i <= slenB; i++) X`09`09printf("sfileB`5B%d`5D = %6d %06o\n", X`09`09`09 i, sfileB`5Bi`5D.serial, sfileB`5Bi`5D.hash); X#endif /* DEBUG */ X`09sort(sfileA, slenA); X`09sort(sfileB, slenB); X#ifdef TIMING X`09ptime("input"); X#endif /* TIMING */ X#ifdef DEBUG X`09printf("after sort\n"); X`09for (i = 1; i <= slenA; i++) X`09`09printf("sfileA`5B%d`5D = %6d %06o\n", X`09`09`09 i, sfileA`5Bi`5D.serial, sfileB`5Bi`5D.hash); X`09for (i = 1; i <= slenB; i++) X`09`09printf("sfileB`5B%d`5D = %6d %06o\n", X`09`09`09 i, sfileB`5Bi`5D.serial, sfileB`5Bi`5D.hash); X#endif /* DEBUG */ X X`09/* X`09 * Build equivalence classes.`20 X`09 */ X`09member = (short *) fileB; X`09equiv(); X`09member = (short *) compact((char *) member, (slenB + 2) * sizeof(int), X`09`09`09`09`09`09`09 "squeezing member vector"); X X`09/* X`09 * Reorder equivalence classes into array class`5B`5D`20 X`09 */ X`09class = (short *) fileA; X`09unsort(); X`09class = (short *) compact((char *) class, (slenA + 2) * sizeof(int), X`09`09`09`09`09`09`09 "compacting class vector"); X#ifdef TIMING X`09ptime("equiv/unsort"); X#endif /* TIMING */ X X`09/* X`09 * Find longest subsequences`20 X`09 */ X`09klist = (int *) myalloc((slenA + 2) * sizeof(int), "klist"); X`09clist = (CANDIDATE *) myalloc(csize * sizeof(CANDIDATE), "clist"); X`09i = subseq(); X#ifndef OSK X`09free((char *) member); X`09free((char *) class); X#else /* OSK */ X`09free((char *) member - sizeof(int)); X`09free((char *) class - sizeof(int)); X#endif /* OSK */ X`09match = (int *) myalloc((lenA + 2) * sizeof(int), "match"); X`09unravel(klist`5Bi`5D); X#ifndef OSK X`09free((char *) clist); X`09free((char *) klist); X#else /* OSK */ X`09free((char *) clist - sizeof(int)); X`09free((char *) klist - sizeof(int)); X#endif /* OSK */ X#ifdef TIMING X`09ptime("subsequence/unravel"); X#endif /* TIMING */ X X`09/* X`09 * Check for fortuitous matches and output differences`20 X`09 */ X`09oldseek = (long *) myalloc((lenA + 2) * sizeof(*oldseek), "oldseek"); X`09newseek = (long *) myalloc((lenB + 2) * sizeof(*newseek), "newseek"); X`09textb = myalloc(sizeof text, "textbuffer"); X`09if (check(argv`5B0`5D, argv`5B1`5D)) X`09`09fprintf(stderr, "Spurious match, output is not optimal\n"); X#ifdef TIMING X`09ptime("check"); X#endif /* TIMING */ X`09output(argv`5B0`5D, argv`5B1`5D); X#ifdef TIMING X`09ptime("output"); X`09printf("%ld seconds required\n", sectiontime - totaltime); X#endif /* TIMING */ X`09if (tempfd != NULL) `7B X`09`09fclose(tempfd); X#ifdef unix X`09`09unlink(TEMPFILE); X#else /* !unix */ X#ifdef OSK X`09`09unlink(TEMPFILE); X#else /* OSK */ X#ifdef MSC`09`09`09`09`09`09/* MSC 4.0 does not understand disjunctive X`09`09`09`09`09`09`09`09 * #if's. */ X`09`09unlink(TEMPFILE); X#else /* MSC */ X`09`09remove(TEMPFILE); X#endif /* MSC */ X#endif /* OSK */ X#endif /* unxi */ X`09`7D X#ifdef VMS X`09exit(0); X#else X`09return(IO_SUCCESS); X#endif X`7D X X X/* X * Read the file, building hash table X */ X Xinput(which) X`09int which;`09`09/* 0 or 1 to redefine infd`5B`5D */ X`7B X`09register LINE *lentry; X`09register int linect = 0; X`09FILE *fd; X#define`09LSIZE_INC 200`09`09`09/* # of line entries to alloc at once */ X`09int lsize = LSIZE_INC; X X`09lentry = (LINE *) myalloc(sizeof(LINE) * (lsize + 3), "line"); X`09fd = infd`5Bwhich`5D; X`09while (!getline(fd, text)) `7B X`09`09if (++linect >= lsize) `7B X`09`09`09lsize += 200; X`09`09`09lentry = (LINE *) compact((char *) lentry, X`09`09`09`09`09`09`09`09`09 (lsize + 3) * sizeof(LINE), X`09`09`09`09`09`09`09`09`09 "extending line vector"); X`09`09`7D X`09`09lentry`5Blinect`5D.hash = hash(text); X`09`7D X X`09/* X`09 * If input was from stdin ("-" command), finish off the temp file.`20 X`09 */ X`09if (fd == stdin) `7B X`09`09fclose(tempfd); X`09`09tempfd = infd`5Bwhich`5D = fopen(TEMPFILE, "r"); X`09`7D X X`09/* X`09 * If we wanted to be stingy with memory, we could realloc lentry down to X`09 * its exact size (+3 for some odd reason) here. No need? `20 X`09 */ X`09len`5Bwhich`5D = linect; X`09file`5Bwhich`5D = lentry; X`7D X X X/* X * Look for initial and trailing sequences that have identical hash values. X * Don't bother building them into the candidate vector. X */ X Xsquish() X`7B X`09register int i; X`09register LINE *ap; X`09register LINE *bp; X`09int j; X`09int k; X X`09/* X`09 * prefix -> first line (from start) that doesn't hash identically`20 X`09 */ X`09i = 0; X`09ap = &fileA`5B1`5D; X`09bp = &fileB`5B1`5D; X`09while (i < lenA && i < lenB && ap->hash == bp->hash) `7B X`09`09i++; X`09`09ap++; X`09`09bp++; X`09`7D X`09prefix = i; X X`09/* X`09 * suffix -> first line (from end) that doesn't hash identically`20 X`09 */ X`09j = lenA - i; X`09k = lenB - i; X`09ap = &fileA`5BlenA`5D; X`09bp = &fileB`5BlenB`5D; X`09i = 0; X`09while (i < j && i < k && ap->hash == bp->hash) `7B X`09`09i++; X`09`09ap--; X`09`09bp--; X`09`7D X`09suffix = i; X X`09/* X`09 * Tuck the counts away`20 X`09 */ X`09for (k = 0; k <= 1; k++) `7B X`09`09sfile`5Bk`5D = file`5Bk`5D + prefix; X`09`09j = slen`5Bk`5D = len`5Bk`5D - prefix - suffix; X X`09`09for (i = 0, ap = sfile`5Bk`5D; i <= slen`5Bk`5D; i++, ap++) `7B X`09`09`09ap->serial = i; X`09`09`7D X`09`7D X`7D X X X/* X * Sort hash entries X */ X Xsort(vector, vecsize) X`09LINE *vector;`09`09/* What to sort `09 */ X`09int vecsize;`09/* How many to sort `09 */ X`7B X`09register int j; X`09register LINE *aim; X`09register LINE *ai; X`09int mid; X`09int k; X`09LINE work; X X`09for (j = 1; j <= vecsize; j *= 2); X`09mid = (j - 1); X`09while ((mid /= 2) != 0) `7B X`09`09k = vecsize - mid; X`09`09for (j = 1; j <= k; j++) `7B X`09`09`09for (ai = &vector`5Bj`5D; ai > vector; ai -= mid) `7B X`09`09`09`09aim = &ai`5Bmid`5D; X`09`09`09`09if (aim < ai) X`09`09`09`09`09break;`09`09/* ?? Why ?? `09 */ X`09`09`09`09if (aim->hash > ai->hash `7C`7C X`09`09`09`09`09aim->hash == ai->hash && X`09`09`09`09`09aim->serial > ai->serial) X`09`09`09`09`09break; X`09`09`09`09work.hash = ai->hash; X`09`09`09`09ai->hash = aim->hash; X`09`09`09`09aim->hash = work.hash; X`09`09`09`09work.serial = ai->serial; X`09`09`09`09ai->serial = aim->serial; X`09`09`09`09aim->serial = work.serial; X`09`09`09`7D X`09`09`7D X`09`7D X`7D X X X/* X * Build equivalence class vector X */ X Xequiv() X`7B X`09register LINE *ap; X`09union `7B X`09`09LINE *bp; X`09`09short *mp; X`09`7D r; X`09register int j; X`09LINE *atop; X X#ifdef DEBUG X`09printf("equiv entry\n"); X`09for (j = 1; j <= slenA; j++) X`09`09printf("sfileA`5B%d`5D = %6d %06o\n", X`09`09`09 j, sfileA`5Bj`5D.serial, sfileA`5Bj`5D.hash); X`09for (j = 1; j <= slenB; j++) X`09`09printf("sfileB`5B%d`5D = %6d %06o\n", X`09`09`09 j, sfileB`5Bj`5D.serial, sfileB`5Bj`5D.hash); X#endif /* DEBUG */ X`09j = 1; X`09ap = &sfileA`5B1`5D; X`09r.bp = &sfileB`5B1`5D; X`09atop = &sfileA`5BslenA`5D; X`09while (ap <= atop && j <= slenB) `7B X`09`09if (ap->hash < r.bp->hash) `7B X`09`09`09ap->hash = 0; X`09`09`09ap++; X`09`09`7D else if (ap->hash == r.bp->hash) `7B X`09`09`09ap->hash = j; X`09`09`09ap++; X`09`09`7D else `7B X`09`09`09r.bp++; X`09`09`09j++; X`09`09`7D X`09`7D X`09while (ap <= atop) `7B X`09`09ap->hash = 0; X`09`09ap++; X`09`7D X`09sfileB`5BslenB + 1`5D.hash = 0; X#ifdef DEBUG X`09printf("equiv exit\n"); X`09for (j = 1; j <= slenA; j++) X`09`09printf("sfileA`5B%d`5D = %6d %06o\n", X`09`09`09 j, sfileA`5Bj`5D.serial, sfileA`5Bj`5D.hash); X`09for (j = 1; j <= slenB; j++) X`09`09printf("sfileB`5B%d`5D = %6d %06o\n", X`09`09`09 j, sfileB`5Bj`5D.serial, sfileB`5Bj`5D.hash); X#endif /* DEBUG */ X`09ap = &sfileB`5B0`5D; X`09atop = &sfileB`5BslenB`5D; X`09r.mp = &member`5B0`5D; X`09while (++ap <= atop) `7B X`09`09r.mp++; X`09`09*r.mp = -(ap->serial); X`09`09while (ap`5B1`5D.hash == ap->hash) `7B X`09`09`09ap++; X`09`09`09r.mp++; X`09`09`09*r.mp = ap->serial; X`09`09`7D X`09`7D X`09r.mp`5B1`5D = -1; X#ifdef DEBUG X`09for (j = 0; j <= slenB; j++) X`09`09printf("member`5B%d`5D = %d\n", j, member`5Bj`5D); X#endif /* DEBUG */ X`7D X X X/* X * Build class vector X */ X Xunsort() X`7B X`09register int *temp; X`09register int *tp; X`09union `7B X`09`09LINE *ap; X`09`09short *cp; X`09`7D u; X`09LINE *evec; X`09short *eclass; X#ifdef DEBUG X`09int i; X#endif /* DEBUG */ X X`09temp = (int *) myalloc((slenA + 1) * sizeof(int), "unsort scratch"); X`09u.ap = &sfileA`5B1`5D; +-+-+-+-+-+-+-+- END OF PART 5 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 6 -+-+-+-+-+-+-+-+ X`09evec = &sfileA`5BslenA`5D; X`09while (u.ap <= evec) `7B X#ifdef DEBUG X`09`09printf("temp`5B%2d`5D := %06o\n", u.ap->serial, u.ap->hash); X#endif /* DEBUG */ X`09`09temp`5Bu.ap->serial`5D = u.ap->hash; X`09`09u.ap++; X`09`7D X X`09/* X`09 * Copy into class vector and free work space`20 X`09 */ X`09u.cp = &class`5B1`5D; X`09eclass = &class`5BslenA`5D; X`09tp = &temp`5B1`5D; X`09while (u.cp <= eclass) X`09`09*u.cp++ = *tp++; X#ifndef OSK X`09free((char *) temp); X#else /* OSK */ X`09free((char *) temp - sizeof(int)); X#endif /* OSK */ X#ifdef DEBUG X`09printf("unsort exit\n"); X`09for (i = 1; i <= slenA; i++) X`09`09printf("class`5B%d`5D = %d %06o\n", i, class`5Bi`5D, class`5Bi`5D); X#endif /* DEBUG */ X`7D X X X/* X * Generate maximum common subsequence chain in clist`5B`5D X */ X Xsubseq() X`7B X`09int a; X`09register unsigned ktop; X`09register int b; X`09register int s; X`09unsigned r; X`09int i; X`09int cand; X X`09klist`5B0`5D = newcand(0, 0, -1); X`09klist`5B1`5D = newcand(slenA + 1, slenB + 1, -1); X`09ktop = 1;`09`09`09`09`09/* -> guard entry */ X`09for (a = 1; a <= slenA; a++) `7B X X`09`09/* X`09`09 * For each non-zero element in fileA ...`20 X`09`09 */ X`09`09if ((i = class`5Ba`5D) == 0) X`09`09`09continue; X`09`09cand = klist`5B0`5D;`09`09/* No candidate now */ X`09`09r = 0;`09`09`09`09`09/* Current r-candidate */ X`09`09do `7B X#ifdef DEBUG X`09`09`09printf("a = %d, i = %d, b = %d\n", a, i, member`5Bi`5D); X#endif /* DEBUG */ X X`09`09`09/* X`09`09`09 * Perform the merge algorithm`20 X`09`09`09 */ X`09`09`09if ((b = member`5Bi`5D) < 0) X`09`09`09`09b = -b; X#ifdef DEBUG X`09`09`09printf("search(%d, %d, %d) -> %d\n", X`09`09`09`09 r, ktop, b, search(r, ktop, b)); X#endif /* DEBUG */ X`09`09`09if ((s = search(r, ktop, b)) != 0) `7B X`09`09`09`09if (clist`5Bklist`5Bs`5D`5D.b > b) `7B X`09`09`09`09`09klist`5Br`5D = cand; X`09`09`09`09`09r = s; X`09`09`09`09`09cand = newcand(a, b, klist`5Bs - 1`5D); X#ifdef DEBUG X`09`09`09`09`09dumpklist(ktop, "klist`5Bs-1`5D->b > b"); X#endif /* DEBUG */ X`09`09`09`09`7D X`09`09`09`09if (s >= ktop) `7B X`09`09`09`09`09klist`5Bktop + 1`5D = klist`5Bktop`5D; X`09`09`09`09`09ktop++; X#ifdef DEBUG X`09`09`09`09`09klist`5Br`5D = cand; X`09`09`09`09`09dumpklist(ktop, "extend"); X#endif /* DEBUG */ X`09`09`09`09`09break; X`09`09`09`09`7D X`09`09`09`7D X`09`09`7D while (member`5B++i`5D > 0); X`09`09klist`5Br`5D = cand; X`09`7D X#ifdef DEBUG X`09printf("last entry = %d\n", ktop - 1); X#endif /* DEBUG */ X`09return (ktop - 1);`09`09`09/* Last entry found */ X`7D X X Xint Xnewcand(a, b, pred) X`09int a;`09`09`09/* Line in fileA `09 */ X`09int b;`09`09`09/* Line in fileB `09 */ X`09int pred;`09`09/* Link to predecessor, index in cand`5B`5D * V/ X`7B X`09register CANDIDATE *new; X X`09clength++; X`09if (++clength >= csize) `7B X`09`09csize += CSIZE_INC; X`09`09clist = (CANDIDATE *) compact((char *) clist, X`09`09`09`09`09`09`09`09`09 csize * sizeof(CANDIDATE), X`09`09`09`09`09`09`09`09`09 "extending clist"); X`09`7D X`09new = &clist`5Bclength - 1`5D; X`09new->a = a; X`09new->b = b; X`09new->link = pred; X`09return (clength - 1); X`7D X X X/* X * Search klist`5Blow..top`5D (inclusive) for b. If klist`5Blow`5D->b >= b, X * return zero. Else return s such that klist`5Bs-1`5D->b < b and X * klist`5Bs`5D->b >= b. Note that the algorithm presupposes the two X * preset "fence" elements, (0, 0) and (slenA, slenB). X */ X Xsearch(low, high, b) X`09register unsigned low; X`09register unsigned high; X`09register int b; X`7B X`09register int temp; X`09register unsigned mid; X X`09if (clist`5Bklist`5Blow`5D`5D.b >= b) X`09`09return (0); X`09while ((mid = (low + high) / 2) > low) `7B X`09`09if ((temp = clist`5Bklist`5Bmid`5D`5D.b) > b) X`09`09`09high = mid; X`09`09else if (temp < b) X`09`09`09low = mid; X`09`09else `7B X`09`09`09return (mid); X`09`09`7D X`09`7D X`09return (mid + 1); X`7D X X Xunravel(k) X`09register int k; X`7B X`09register int i; X`09register CANDIDATE *cp; X`09int first_trailer; X`09int difference; X X`09first_trailer = lenA - suffix; X`09difference = lenB - lenA; X#ifdef DEBUG X`09printf("first trailer = %d, difference = %d\n", X`09`09 first_trailer, difference); X#endif /* DEBUG */ X`09for (i = 0; i <= lenA; i++) `7B X`09`09match`5Bi`5D = (i <= prefix) ? i X`09`09`09: (i > first_trailer) ? i + difference X`09`09`09: 0; X`09`7D X#ifdef DEBUG X`09printf("unravel\n"); X#endif /* DEBUG */ X`09while (k != -1) `7B X`09`09cp = &clist`5Bk`5D; X#ifdef DEBUG X`09`09if (k < 0 `7C`7C k >= clength) X`09`09`09error("Illegal link -> %d", k); X`09`09printf("match`5B%d`5D := %d\n", cp->a + prefix, cp->b + prefix); X#endif /* DEBUG */ X`09`09match`5Bcp->a + prefix`5D = cp->b + prefix; X`09`09k = cp->link; X`09`7D X`7D X X X/* X * Check for hash matches (jackpots) and collect random access indices to X * the two files. X * X * It should be possible to avoid doing most of the ftell's by noticing X * that we are not doing a context diff and noticing that if a line X * compares equal to the other file, we will not ever need to know its X * file position. FIXME. X */ X Xcheck(fileAname, fileBname) X`09char *fileAname; X`09char *fileBname; X`7B X`09register int a;`09`09`09/* Current line in file A */ X`09register int b;`09`09`09/* Current line in file B */ X`09int jackpot; X X`09b = 1; X`09fclose(infd`5B0`5D); X`09infd`5B0`5D = fopen(fileAname, "r" X#ifdef VMS X`09`09`09`09 , "mbc=64", "mbf=2" X#endif X`09`09`09`09`09); X`09infd`5B1`5D = fopen(fileBname, "r" X#ifdef VMS X`09`09`09`09 , "mbc=64", "mbf=2" X#endif X`09`09`09`09`09); X/* X * See above; these would be over-written on VMS anyway. X */ X X#ifndef vms X`09oldseek`5B0`5D = ftell(infd`5B0`5D); X`09newseek`5B0`5D = ftell(infd`5B1`5D); X#endif /* vms */ X X`09jackpot = 0; X#ifdef DEBUG X`09printf("match vector\n"); X`09for (a = 0; a <= lenA; a++) X`09`09printf("match`5B%d`5D = %d\n", a, match`5Ba`5D); X#endif /* DEBUG */ X`09for (a = 1; a <= lenA; a++) `7B X`09`09if (match`5Ba`5D == 0) `7B X`09`09`09/* Unique line in A */ X`09`09`09oldseek`5Ba`5D = ftell(infd`5B0`5D); X`09`09`09getline(infd`5B0`5D, text); X`09`09`09continue; X`09`09`7D X`09`09while (b < match`5Ba`5D) `7B X`09`09`09/* Skip over unique lines in B */ X`09`09`09newseek`5Bb`5D = ftell(infd`5B1`5D); X`09`09`09getline(infd`5B1`5D, textb); X`09`09`09b++; X`09`09`7D X X`09`09/* X`09`09 * Compare the two, supposedly matching, lines. Unless we are going X`09`09 * to print these lines, don't bother to remember where they are. We X`09`09 * only print matching lines if a context diff is happening, or if a X`09`09 * jackpot occurs.`20 X`09`09 */ X`09`09if (cflag) `7B X`09`09`09oldseek`5Ba`5D = ftell(infd`5B0`5D); X`09`09`09newseek`5Bb`5D = ftell(infd`5B1`5D); X`09`09`7D X`09`09getline(infd`5B0`5D, text); X`09`09getline(infd`5B1`5D, textb); X`09`09if (!streq(text, textb)) `7B X`09`09`09fprintf(stderr, "Spurious match:\n"); X`09`09`09fprintf(stderr, "line %d in %s, \"%s\"\n", X`09`09`09`09`09a, fileAname, text); X`09`09`09fprintf(stderr, "line %d in %s, \"%s\"\n", X`09`09`09`09`09b, fileBname, textb); X`09`09`09match`5Ba`5D = 0; X`09`09`09jackpot++; X`09`09`7D X`09`09b++; X`09`7D X`09for (; b <= lenB; b++) `7B X`09`09newseek`5Bb`5D = ftell(infd`5B1`5D); X`09`09getline(infd`5B1`5D, textb); X`09`7D X/* X * The logical converse to the code up above, for NON-VMS systems, to X * store away an fseek() pointer at the beginning of the file. For VMS, X * we need one at EOF... X */ X X#ifdef VMS X`09oldseek`5BlenA`5D = ftell(infd`5B0`5D); X`09getline(infd`5B0`5D, text);`09`09/* Will hit EOF... */ X`09newseek`5BlenB`5D = ftell(infd`5B1`5D); X`09getline(infd`5B1`5D, textb);`09/* Will hit EOF... */ X#endif /* vms */ X X`09return (jackpot); X`7D X X Xoutput(fileAname, fileBname) X`09char *fileAname, *fileBname; X`7B X`09register int astart; X`09register int aend = 0; X`09int bstart; X`09register int bend; X X`09rewind(infd`5B0`5D); X`09rewind(infd`5B1`5D); X`09match`5B0`5D = 0; X`09match`5BlenA + 1`5D = lenB + 1; X`09if (!eflag) `7B X`09`09if (cflag) `7B X X`09`09`09/* X`09`09`09 * Should include ctime style dates after the file names, but X`09`09`09 * this would be non-trivial on OSK. Perhaps there should be a X`09`09`09 * special case for stdin.`20 X`09`09`09 */ X`09`09`09printf("*** %s\n--- %s\n", fileAname, fileBname); X`09`09`7D X X`09`09/* X`09`09 * Normal printout`20 X`09`09 */ X`09`09for (astart = 1; astart <= lenA; astart = aend + 1) `7B X X`09`09`09/* X`09`09`09 * New subsequence, skip over matching stuff`20 X`09`09`09 */ X`09`09`09while (astart <= lenA X`09`09`09`09 && match`5Bastart`5D == (match`5Bastart - 1`5D + 1)) X`09`09`09`09astart++; X X`09`09`09/* X`09`09`09 * Found a difference, setup range and print it`20 X`09`09`09 */ X`09`09`09bstart = match`5Bastart - 1`5D + 1; X`09`09`09aend = astart - 1; X`09`09`09while (aend < lenA && match`5Baend + 1`5D == 0) X`09`09`09`09aend++; X`09`09`09bend = match`5Baend + 1`5D - 1; X`09`09`09match`5Baend`5D = bend; X`09`09`09change(astart, aend, bstart, bend); X`09`09`7D X`09`7D else `7B X X`09`09/* X`09`09 * Edit script output -- differences are output "backwards" for the X`09`09 * benefit of a line-oriented editor.`20 X`09`09 */ X`09`09for (aend = lenA; aend >= 1; aend = astart - 1) `7B X`09`09`09while (aend >= 1 X`09`09`09`09 && match`5Baend`5D == (match`5Baend + 1`5D - 1) X`09`09`09`09 && match`5Baend`5D != 0) X`09`09`09`09aend--; X`09`09`09bend = match`5Baend + 1`5D - 1; X`09`09`09astart = aend + 1; X`09`09`09while (astart > 1 && match`5Bastart - 1`5D == 0) X`09`09`09`09astart--; X`09`09`09bstart = match`5Bastart - 1`5D + 1; X`09`09`09match`5Bastart`5D = bstart; X`09`09`09change(astart, aend, bstart, bend); X`09`09`7D X`09`7D X`09if (lenA == 0) X`09`09change(1, 0, 1, lenB); X`7D X X X/* X * Output a change entry: fileA`5Bastart..aend`5D changed to fileB`5Bbstart. V.bend`5D X */ X Xchange(astart, aend, bstart, bend) X`09int astart; X`09int aend; X`09int bstart; X`09int bend; X`7B X`09char c; X X`09/* X`09 * This catches a "dummy" last entry`20 X`09 */ X`09if (astart > aend && bstart > bend) X`09`09return; X`09c = (astart > aend) ? 'a' : (bstart > bend) ? 'd' : 'c'; X`09if (cflag) X`09`09fputs("**************\n*** ", stdout); X X`09if (c == 'a' && !cflag) X`09`09range(astart - 1, astart - 1, 0);`09`09/* Addition: just print one X`09`09`09`09`09`09`09`09`09`09`09`09 * odd # */ X`09else X`09`09range(astart, aend, 0);`09/* Print both, if different */ X`09if (!cflag) `7B X`09`09putchar(c); X`09`09if (!eflag) `7B X`09`09`09if (c == 'd') X`09`09`09`09range(bstart - 1, bstart - 1, 1);`09`09/* Deletion: just print X`09`09`09`09`09`09`09`09`09`09`09`09`09`09 * one odd # */ X`09`09`09else X`09`09`09`09range(bstart, bend, 1);`09/* Print both, if different */ X`09`09`7D X`09`7D X`09putchar('\n'); X`09if ((!eflag && c != 'a') `7C`7C cflag) `7B X`09`09fetch(oldseek, astart, aend, lenA, infd`5B0`5D, X`09`09`09 cflag ? (c == 'd' ? "- " : "! ") : "< "); X`09`09if (cflag) `7B X`09`09`09fputs("--- ", stdout); X`09`09`09range(bstart, bend, 1); X`09`09`09fputs(" -----\n", stdout); X`09`09`7D else if (astart <= aend && bstart <= bend) X`09`09`09printf("---\n"); X`09`7D X`09fetch(newseek, bstart, bend, lenB, infd`5B1`5D, X`09`09 cflag ? (c == 'a' ? "+ " : "! ") : (eflag ? "" : "> ")); X`09if (eflag && bstart <= bend) X`09`09printf(".\n"); X`7D X X X/* X * Print a range X */ X Xrange(from, to, w) X`09int from; X`09int to; X`09int w; X`7B X`09if (cflag) `7B X`09`09if ((from -= cflag) <= 0) X`09`09`09from = 1; X`09`09if ((to += cflag) > len`5Bw`5D) X`09`09`09to = len`5Bw`5D; X`09`7D X`09if (to > from) `7B X`09`09printf("%d,%d", from, to); X`09`7D else if (to < from) `7B X`09`09printf("%d,%d", to, from); X`09`7D else `7B X`09`09printf("%d", from); X`09`7D X`7D X X X/* X * Print the appropriate text X */ X Xfetch(seekvec, start, end, trueend, fd, pfx) X`09long *seekvec; X`09register int start; X`09register int end; X`09int trueend; X`09FILE *fd; X`09char *pfx; X`7B X`09register int i; X`09register int first; X`09register int last; X X`09if (cflag) `7B X`09`09if ((first = start - cflag) <= 0) X`09`09`09first = 1; X`09`09if ((last = end + cflag) > trueend) X`09`09`09last = trueend; X`09`7D else `7B X`09`09first = start; X`09`09last = end; X`09`7D X`09if (fseek(fd, seekvec`5Bfirst`5D, 0) != 0) `7B X`09`09printf("?Can't read line %d at %08lx (hex) in file%c\n", X`09`09`09 start, seekvec`5Bfirst`5D, X`09`09`09 (fd == infd`5B0`5D) ? 'A' : 'B'); X`09`7D else `7B X`09`09for (i = first; i <= last; i++) `7B X`09`09`09if (fgetss(text, sizeof text, fd) == NULL) `7B X`09`09`09`09printf("** Unexpected end of file\n"); X`09`09`09`09break; X`09`09`09`7D X#ifdef DEBUG X`09`09`09printf("%5d: %s%s\n", i, pfx, text); X#else /* !DEBUG */ X`09`09`09fputs((cflag && (i < start `7C`7C i > end)) ? " " : pfx, stdout); X`09`09`09fputs(text, stdout); X`09`09`09putchar('\n'); X#endif /* DEBUG */ X`09`09`7D X`09`7D X`7D X X X/* X * Input routine, read one line to buffer`5B`5D, return TRUE on eof, else FA VLSE. X * The terminating newline is always removed. If "-b" was given, trailing X * whitespace (blanks and tabs) are removed and strings of blanks and X * tabs are replaced by a single blank. Getline() does all hacking for X * redirected input files. X */ X Xint Xgetline(fd, buffer) X`09FILE *fd; X`09char *buffer; X`7B X`09register char *top; X`09register char *fromp; X`09register char c; X X`09if (fgetss(buffer, sizeof text, fd) == NULL) `7B X`09`09*buffer = EOS; X`09`09return (TRUE); X`09`7D X`09if (fd == stdin) X`09`09fputss(buffer, tempfd); X`09if (bflag `7C`7C iflag) `7B X`09`09top = buffer; X`09`09fromp = buffer; X`09`09while ((c = *fromp++) != EOS) `7B X`09`09`09if (bflag && (c == ' ' `7C`7C c == '\t')) `7B X`09`09`09`09c = ' '; +-+-+-+-+-+-+-+- END OF PART 6 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 7 -+-+-+-+-+-+-+-+ X`09`09`09`09while (*fromp == ' ' `7C`7C *fromp == '\t') X`09`09`09`09`09fromp++; X`09`09`09`7D X`09`09`09if (iflag) X`09`09`09`09c = tolower(c); X`09`09`09*top++ = c; X`09`09`7D X`09`09if (bflag && top`5B-1`5D == ' ') X`09`09`09top--; X`09`09*top = EOS; X`09`7D X`09return (FALSE); X`7D X X Xstatic unsigned short crc16a`5B`5D = `7B X`09`09`09`09`09`09`09`09 0000000, 0140301, 0140601, 0000500, X`09`09`09`09`09`09`09`09 0141401, 0001700, 0001200, 0141101, X`09`09`09`09`09`09`09`09 0143001, 0003300, 0003600, 0143501, X`09`09`09`09`09`09`09`09 0002400, 0142701, 0142201, 0002100, X`7D; X Xstatic unsigned short crc16b`5B`5D = `7B X`09`09`09`09`09`09`09`09 0000000, 0146001, 0154001, 0012000, X`09`09`09`09`09`09`09`09 0170001, 0036000, 0024000, 0162001, X`09`09`09`09`09`09`09`09 0120001, 0066000, 0074000, 0132001, X`09`09`09`09`09`09`09`09 0050000, 0116001, 0104001, 0043000, X`7D; X X X/* X * Return the CRC16 hash code for the buffer X * Algorithm from Stu Wecker (Digital memo 130-959-002-00). X */ X Xunsigned short Xhash(buffer) X`09char *buffer; X`7B X`09register unsigned short crc; X`09register char *tp; X`09register short temp; X X`09crc = 0; X`09for (tp = buffer; *tp != EOS;) `7B X`09`09temp = *tp++ `5E crc;`09`09/* XOR crc with new char */ X`09`09crc = (crc >> 8) X`09`09`09`5E crc16a`5B(temp & 0017)`5D X`09`09`09`5E crc16b`5B(temp & 0360) >> 4`5D; X`09`7D X#ifdef DEBUG_ALL X`09printf("%06o: %s\n", (crc == 0) ? 1 : crc, buffer); X#endif /* DEBUG_ALL */ X`09return ((crc == 0) ? (unsigned short) 1 : crc); X`7D X X X#ifdef VMS Xopendir(which, arg, okfd) X`09int which;`09`09/* Which file to open (0 or 1) `09 */ X`09char **arg;`09`09/* File name argument, &argv`5Bwhich`5D */ X`09FILE *okfd;`09`09/* File name (already open) `09 */ X`7B X`09char defaultname`5B512`5D; X`09char *c; X X`09fgetname(okfd, text); X`09if (c = strrchr(text, ';')) X`09`09*c = '\0'; X`09for (c=text; *c; ++c) X`09`09if (isupper(*c)) X`09`09`09*c = _tolower(*c); X`09sprintf(defaultname, "dna=%s", text); X X`09if ((infd`5Bwhich`5D = fopen(*arg, "r", defaultname, "mbc=64", "mbf=2")) V == NULL) X`09`09cant(*arg, "constructed input", 1); X`09fgetname(infd`5Bwhich`5D, text); X`09*arg = malloc(strlen(text)+1); X`09strcpy(*arg, text); X`7D X Xprevious_version(file) X`09char *file; X`7B X`09FILE *f; X`09static char`09name`5B256`5D; X`09char `09`09*p; X`09int`09`09version; X X`09if (NULL == (f = fopen(file, "r"))) X`09`09return(NULL); X`09fgetname(f, name); X`09fclose(f); X`09p = strrchr(name, ';'); X`09version = strtol(p+1, NULL, 0); X`09while (--version) `7B X`09`09sprintf(p+1, "%d", version); X`09`09if (f = fopen(name, "r")) `7B X`09`09`09fclose(f); X`09`09`09return(name); X`09`09`7D X`09`7D X`09return(NULL); X`7D`09 X X/* Amiga C doesn't have all these extensions for directory... */ X#endif /* vms */ X X X/* X * Allocate or crash. X */ X Xchar * Xmyalloc(amount, why) X`09unsigned amount; X`09char *why; X`7B X`09register char *pointer; X X#ifdef OSK X`09amount += sizeof(int); X#endif /* OSK */ X`09if ((pointer = malloc((unsigned) amount)) == NULL) X`09`09noroom(why); X#ifdef OSK X`09*((int *) pointer) = amount; X`09pointer += sizeof(int); X#ifdef DEBUG X`09fprintf(stderr, "Myalloc: %d at %06o\n", amount, pointer); X#endif /* DEBUG */ X#endif /* OSK */ X#ifdef`09AMIGA X`09savsiz = amount; X`09savptr = pointer; X#endif /* AMIGA */ X X`09return (pointer); X`7D X X X/* X * Reallocate pointer, compacting storage X * X * The "compacting storage" part is probably not relevant any more. X * There used to be horrid code here that malloc'd one byte and freed X * it at magic times, to cause garbage collection of the freespace X * or something. It's safely gone now, you didn't have to see it. X *`09-- John Gilmore, Nebula Consultants, Sept 26, 1986 X */ X Xchar * Xcompact(pointer, new_amount, why) X`09char *pointer; X`09unsigned new_amount; X`09char *why; X`7B X`09register char *new_pointer; X X#ifndef AMIGA X#ifndef OSK X#ifdef TURBO X`09extern void *realloc(); X#else /* !TURBO */ X`09extern char *realloc(); X#endif /* TURBO */ X X`09if ((new_pointer = realloc(pointer, (unsigned) new_amount)) == NULL) `7B X`09`09noroom(why); X`09`7D X#else /* OSK */ X`09register int old_amount; X`09new_amount += sizeof(int); X`09if ((new_pointer = malloc(new_amount)) == NULL) X`09`09noroom(why); X`09*(int *) new_pointer = new_amount; X`09new_pointer += sizeof(int); X`09old_amount = *(((int *) pointer) - 1); X`09/* _strass is like bcopy with the first two arguments reversted */ X`09_strass(new_pointer, pointer, (new_amount <= old_amount ? X`09`09`09`09`09`09`09`09 new_amount : old_amount) - sizeof(int)); X#ifdef DEBUG X`09fprintf(stderr, "compact %d to %d from %06o to %06o\n", X`09`09`09old_amount, new_amount, pointer, new_pointer); X#endif /* DEBUG */ X`09free(pointer - sizeof(int)); X#endif /* OSK */ X#else /* AMIGA */ X X`09/* X`09 * This routine is heavily dependent on C storage allocator hacks For X`09 * Amiga, we can't rely on storage being left alone "up to" the boundary X`09 * of allocation as in VMS or RSX. Therefore we have to be different here X`09 * and allocate a new larger segment, then free the old one. Messy but X`09 * hopefully it will work.`20 X`09 */ X`09extern char *malloc(); X X`09/* No realloc(). Do a malloc and copy it. */ X`09if ((new_pointer = malloc((unsigned) new_amount)) == NULL) `7B X`09`09noroom(why); X`09`7D X /* This MUST assume the program calls compact using the old pointer as the X last call of malloc... Reason is that RSX version is really simpleminded * V/ X`09cpysiz = savsiz; X /* Complain if deallocate area not same as last allocate area */ X`09if (savptr != pointer) X`09`09bogus(why); X`09wrk2 = new_pointer; X`09for (wrk = pointer; cpysiz > 0; cpysiz--) `7B X /* copy data to new area */ X`09`09*wrk2++ = *wrk++; X`09`7D X /* when done, free old memory area. */ X`09free(pointer); X#endif /* AMIGA */ X X#ifndef OSK X#ifdef DEBUG X`09if (new_pointer != pointer) `7B X`09`09fprintf(stderr, "moved from %06o to %06o\n", X`09`09`09`09pointer, new_pointer); X`09`7D X/* rdump(new_pointer, why); X*/ X#endif /* DEBUG */ X#endif /* OSK */ X`09return (new_pointer); X`7D X X Xnoroom(why) X`09char *why; X`7B X`09fprintf(stderr, "?DIFF-F-out of room when %s\n", why); X`09exit(IO_ERROR); X`7D X X X#ifdef`09AMIGA Xbogus(why) X`09char *why; X`7B X`09fprintf(stderr, "?DIFF-F-invalid compaction when %s\n", why); X`09exit(IO_ERROR); X`7D X#endif`09/* AMIGA */ X X X#ifdef DEBUG X/* X * Dump memory block X */ X Xrdump(pointer, why) X`09int *pointer; X`09char *why; X`7B X`09int *last; X`09int count; X X`09last = ((int **) pointer)`5B-1`5D; X`09fprintf(stderr, "dump %s of %06o -> %06o, %d words", X`09`09`09why, pointer, last, last - pointer); X`09last = (int *) (((int) last) & `7E1); X`09for (count = 0; pointer < last; ++count) `7B X`09`09if ((count & 07) == 0) `7B X`09`09`09fprintf(stderr, "\n%06o", pointer); X`09`09`7D X`09`09fprintf(stderr, "\t%06o", *pointer); X`09`09pointer++; X`09`7D X`09fprintf(stderr, "\n"); X`7D X#endif /* DEBUG */ X X X/* X * Can't open file message X */ X Xcant(filename, what, fatalflag) X`09char *filename; X`09char *what; X`09int fatalflag; X`7B X`09fprintf(stderr, "Can't open %s file \"%s\": ", what, filename); X#ifndef`09OSK X`09perror(""); X#else X`09prerr(0, errno); X#endif X`09if (fatalflag) `7B X`09`09exit(fatalflag); X`09`7D X`7D X X X#ifdef DEBUG Xdump(d_linep, d_len, d_which) X`09LINE *d_linep; X`09int`09`09`09`09d_len; X`09int`09`09`09`09d_which; X`7B X`09register int i; X X`09printf("Dump of file%c, %d elements\n", "AB"`5Bd_which`5D, d_len); X`09printf("linep @ %06o\n", d_linep); X`09for (i = 0; i <= d_len; i++) `7B X`09`09printf("%3d %6d %06o\n", i, X`09`09`09 d_linep`5Bi`5D.serial, d_linep`5Bi`5D.hash); X`09`7D X`7D X X X/* X * Dump klist X */ X Xdumpklist(kmax, why) X`09int kmax; X`09char *why; X`7B X`09register int i; X`09register CANDIDATE *cp; X`09register int count; X X`09printf("\nklist`5B0..%d`5D %s, clength = %d\n", kmax, why, clength); X`09for (i = 0; i <= kmax; i++) `7B X`09`09cp = &clist`5Bklist`5Bi`5D`5D; X`09`09printf("%2d %2d", i, klist`5Bi`5D); X`09`09if (cp >= &clist`5B0`5D && cp < &clist`5Bclength`5D) X`09`09`09printf(" (%2d %2d -> %2d)\n", cp->a, cp->b, cp->link); X`09`09else if (klist`5Bi`5D == -1) X`09`09`09printf(" End of chain\n"); X`09`09else X`09`09`09printf(" illegal klist element\n"); X`09`7D X`09for (i = 0; i <= kmax; i++) `7B X`09`09count = -1; X`09`09for (cp = (CANDIDATE *) klist`5Bi`5D; cp > &clist`5B0`5D; X`09`09`09 cp = (CANDIDATE *) & cp->link) `7B X`09`09`09if (++count >= 6) `7B X`09`09`09`09printf("\n "); X`09`09`09`09count = 0; X`09`09`09`7D X`09`09`09printf(" (%2d: %2d,%2d -> %d)", X`09`09`09`09 cp - clist, cp->a, cp->b, cp->link); X`09`09`7D X`09`09printf("\n"); X`09`7D X`09printf("*\n"); X`7D X#endif`09/* DEBUG */ X X X X#ifdef TIMING X X/* X * Dump time buffer X */ X Xptime(why) X`09char *why; X`7B X`09long ttemp; X X`09ttemp = time(NULL); X`09printf("%ld seconds for %s\n", X`09`09 ttemp - sectiontime, why); X`09sectiontime = ttemp; X`7D X#endif`09/* TIMING */ X X X/* X * TRUE if strings are identical X */ X Xint Xstreq(s1, s2) X`09register char *s1; X`09register char *s2; X`7B X`09while (*s1++ == *s2) `7B X`09`09if (*s2++ == EOS) X`09`09`09return (TRUE); X`09`7D X`09return (FALSE); X`7D X X X/* X * Error message before retiring. X */ X X/* VARARGS */ Xerror(format, args) X`09char *format; X`7B X`09fprintf(stderr, format, &args); X`09putc('\n', stderr); X`09_error(); X`7D X X X_error() X`7B X`09exit(1); X`7D X X X/* X * Like fput() except that it puts a newline at the end of the line. X */ X Xfputss(s, iop) X`09register char *s; X`09register FILE *iop; X`7B X`09fputs(s, iop); X`09putc('\n', iop); X`7D X X X/* X * Fgetss() is like fgets() except that the terminating newline X * is removed.`20 X */ X Xchar * Xfgetss(s, n, iop) X`09char *s; X`09register FILE *iop; X`7B X`09register char *cs; X X`09if (fgets(s, n, iop) == NULL) X`09`09return ((char *) NULL); X`09cs = s + strlen(s) - 1; X`09if (*cs == '\n') X`09`09*cs = '\0'; X`09return (s); X`7D $ CALL UNPACK [.SRC]DIFF.C;1 21876700 $ create 'f' X/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $ X * X * $Log:`09EXTERN.h,v $ X * Revision 2.0 86/09/17 15:35:37 lwall X * Baseline for netwide release. X *`20 X */ X X#undef EXT X#define EXT extern X X#undef INIT X#define INIT(x) X X#undef DOINIT $ CALL UNPACK [.SRC]EXTERN.H;1 572608833 $ create 'f' X/* X * @(#)includes.h 1.8 89/04/01`09`09Jamie Hanrahan (simpact!jeh) X * X * Version simpact-1.8, for DECUS uucp (VMS portion). `20 X * All changes and additions from previous versions (see below) are in X * the public domain.`20 X * X * Derived from: X *`20 X * includes.h 1.7 87/09/29`09Copyright 1987 Free Software Foundation, Inc. X * X * Copying and use of this program are controlled by the terms of the X * GNU Emacs General Public License. X * X * Include files for various supported systems: X * Note that NAMESIZE should be the max length of a file name, including X * all its directories, drive specifiers, extensions, and the like. X * E.g. on a Unix with 14-char file names, NAMESIZE is several hundred X * characters, since the 14-char names can be nested. X */ X X#include ctype X#include descrip X#include dvidef X#include errno X#include file X#include iodef X#include math X#include setjmp X#include signal X#include ssdef X#include stat X#include stdlib`20 X#include stdio X#include string X#include time X X#define NAMESIZE 255 X#define UUXQT_DOORBELL "UUCP_UUXQT_DOORBELL" X#define UUCICO_REQMB "UUCP_REQUESTS" X#define`09UUX_QUEUE "UUCP_BATCH_QUEUE" X#define`09UUX_FILE "UUCP_BIN:UUXQT_BATCH.COM" X#define DEBUG_LOG_FILE "vmsnet_log:uucico_dbg" X#define`09UUX_LOG "UUCP_LOG:UUXQT.LOG" X#define`09SYSLOCK_TEMPLATE "UUCP_SYS_%s" X#define STATUS_LNT "LNM$SYSTEM_TABLE" X#define STATUS_TEMPLATE "UUCP_STATUS_%s" X#define MAXLOCK 32 X#define LOGLEN 255 X#define SEQSIZE 4 X#define CONTROL_FILE "uucp_cfg:control."`20 X#define`09LOGCLOSE`09/* Logfile must be closed; VMS locks it when open */ X#define EXEDIR "uucp_bin:"`09/* uuxqt executables live here (not used) */ X#define NULL_DEVICE "NL:" X#define fork vfork`09`09/* (not used) */ X#define STATUS int`09`09/* (not used) */ X#define postmaster "UUCP_POSTMASTER" X#define EXIT_OK 1`09`09/* image exit code */ X#define EXIT_ERR 0x10000000`09/* image exit code */ X#define ENABLE 1`09`09/* for $SETAST (and maybe others) */ X#define DISABLE 0 X#define`09time_t`09unsigned`09/* (not used) */ X#define remove delete`09/* Remove a file */ X#define qsort pqsort`09/* Our own version (not used) */ X X#define FOPEN_W_MODE "w"`09/* mode to open files being received */ X#define FOPEN_R_MODE "r"`09/* or sent */ X X#define SS_FAILED(status) (((status)&1) == 0) X#define initdsc(d) d.dsc$b_class = DSC$K_CLASS_S, d.dsc$b_dtype = DSC$K_DTYP VE_T X#define fillindsc(d, s) d.dsc$w_length=strlen(s), d.dsc$a_pointer=(s) X#define init_itmlst3(e,i,l,c,a,r) \ X`09(e`5Bi`5D.len=(l),\ X`09e`5Bi`5D.code=(c),\ X`09e`5Bi`5D.address=(a),\ X`09e`5Bi`5D.retlen=(r)) X $ CALL UNPACK [.SRC]INCLUDES.H;1 1900750121 $ create 'f' X/* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $ X * X * $Log:`09inp.c,v $ X * Revision 2.0 86/09/17 15:37:02 lwall X * Baseline for netwide release. X *`20 X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "pch.h" X#include "INTERN.h" X#include "inp.h" X X/* Input-file-with-indexable-lines abstract type */ X Xstatic long i_size;`09`09`09/* size of the input file */ Xstatic char *i_womp;`09`09`09/* plan a buffer for entire file */ Xstatic char **i_ptr;`09`09`09/* pointers to lines in i_womp */ X +-+-+-+-+-+-+-+- END OF PART 7 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 8 -+-+-+-+-+-+-+-+ Xstatic int tifd = -1;`09`09`09/* plan b virtual string array */ Xstatic char *tibuf`5B2`5D;`09`09`09/* plan b buffers */ Xstatic LINENUM tiline`5B2`5D = `7B-1, -1`7D;`09/* 1st line in each buffer */ Xstatic LINENUM lines_per_buf;`09`09/* how many lines per buffer */ Xstatic int tireclen;`09`09`09/* length of records in tmp file */ X X/* New patch--prepare to edit another file. */ X Xvoid Xre_input() X`7B X if (using_plan_a) `7B X`09i_size = 0; X#ifndef lint X`09if (i_ptr != Null(char**)) X`09 free((char *)i_ptr); X#endif X`09if (i_womp != Nullch) X`09 free(i_womp); X`09i_womp = Nullch; X`09i_ptr = Null(char **); X `7D X else `7B X`09using_plan_a = TRUE;`09`09/* maybe the next one is smaller */ X`09Close(tifd); X`09tifd = -1; X`09free(tibuf`5B0`5D); X`09free(tibuf`5B1`5D); X`09tibuf`5B0`5D = tibuf`5B1`5D = Nullch; X`09tiline`5B0`5D = tiline`5B1`5D = -1; X`09tireclen = 0; X `7D X`7D X X/* Constuct the line index, somehow or other. */ X Xvoid Xscan_input(filename) Xchar *filename; X`7B X if (!plan_a(filename)) X`09plan_b(filename); X if (verbose) `7B X`09say3("Patching file %s using Plan %s...\n", filename, X`09 (using_plan_a ? "A" : "B") ); X `7D X`7D X X/* Try keeping everything in memory. */ X Xbool Xplan_a(filename) Xchar *filename; X`7B X int ifd; X Reg1 char *s; X Reg2 LINENUM iline; X X if (ok_to_create_file && stat(filename, &filestat) < 0) `7B X`09if (verbose) X`09 say2("(Creating file %s...)\n",filename); X`09makedirs(filename, TRUE); X`09close(creat(filename, 0666)); X `7D X if (stat(filename, &filestat) < 0) `7B X`09Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX); X`09if (stat(buf, &filestat) >= 0 `7C`7C stat(buf+4, &filestat) >= 0) `7B X`09 Sprintf(buf, CHECKOUT, filename); X`09 if (verbose) X`09`09say2("Can't find %s--attempting to check it out from RCS.\n", X`09`09 filename); X`09 if (system(buf) `7C`7C stat(filename, &filestat)) X`09`09fatal2("Can't check out %s.\n", filename); X`09`7D X`09else `7B X`09 Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename); X`09 if (stat(buf, &filestat) >= 0 `7C`7C stat(buf+5, &filestat) >= 0) `7B X`09`09Sprintf(buf, GET, filename); X`09`09if (verbose) X`09`09 say2("Can't find %s--attempting to get it from SCCS.\n", X`09`09`09filename); X`09`09if (system(buf) `7C`7C stat(filename, &filestat)) X`09`09 fatal2("Can't get %s.\n", filename); X`09 `7D X`09 else X`09`09fatal2("Can't find %s.\n", filename); X`09`7D X `7D X filemode = filestat.st_mode; X if ((filemode & S_IFMT) & `7ES_IFREG) X`09fatal2("%s is not a normal file--can't patch.\n", filename); X i_size = filestat.st_size; X if (out_of_mem) `7B X`09set_hunkmax();`09`09/* make sure dynamic arrays are allocated */ X`09out_of_mem = FALSE; X`09return FALSE;`09`09`09/* force plan b because plan a bombed */ X `7D X#ifdef lint X i_womp = Nullch; X#else X i_womp = malloc((MEM)(i_size+2));`09/* lint says this may alloc less tha Vn */ X`09`09`09`09`09/* i_size, but that's okay, I think. */ X#endif X if (i_womp == Nullch) X`09return FALSE; X if ((ifd = open(filename, 0 X#ifdef VMS X`09`09`09`09,"mbc=64", "mbf=2" X#endif X`09`09`09`09)) < 0) X`09fatal2("Can't open file %s\n", filename); X#ifndef lint X#ifdef VMS X `7B X int ind = 0, count; X X while (ind < i_size) `7B X`09if (0 >= (count = read(ifd, &i_womp`5Bind`5D, (int)(i_size-ind)))) X`09 break; X`09ind += count;`09 X `7D X i_size = ind; X `7D X#else X if (read(ifd, i_womp, (int)i_size) != i_size) `7B X`09Close(ifd);`09/* probably means i_size > 15 or 16 bits worth */ X`09free(i_womp);`09/* at this point it doesn't matter if i_womp was */ X`09return FALSE;`09/* undersized. */ X `7D X#endif X#endif X Close(ifd); X if (i_size && i_womp`5Bi_size-1`5D != '\n') X`09i_womp`5Bi_size++`5D = '\n'; X i_womp`5Bi_size`5D = '\0'; X X /* count the lines in the buffer so we know how many pointers we need */ X X iline = 0; X for (s=i_womp; *s; s++) `7B X`09if (*s == '\n') X`09 iline++; X `7D X#ifdef lint X i_ptr = Null(char**); X#else X i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *))); X#endif X if (i_ptr == Null(char **)) `7B`09/* shucks, it was a near thing */ X`09free((char *)i_womp); X`09return FALSE; X `7D X `20 X /* now scan the buffer and build pointer array */ X X iline = 1; X i_ptr`5Biline`5D = i_womp; X for (s=i_womp; *s; s++) `7B X`09if (*s == '\n') X`09 i_ptr`5B++iline`5D = s+1;`09/* these are NOT null terminated */ X `7D X input_lines = iline - 1; X X /* now check for revision, if any */ X X if (revision != Nullch) `7B`20 X`09if (!rev_in_string(i_womp)) `7B X`09 if (force) `7B X`09`09if (verbose) X`09`09 say2("\ XWarning: this file doesn't appear to be the %s version--patching anyway.\n", X`09`09`09revision); X`09 `7D X`09 else `7B X`09`09ask2("\ XThis file doesn't appear to be the %s version--patch anyway? `5Bn`5D ", X`09`09 revision); X`09 if (*buf != 'y') X`09`09fatal1("Aborted.\n"); X`09 `7D X`09`7D X`09else if (verbose) X`09 say2("Good. This file appears to be the %s version.\n", X`09`09revision); X `7D X return TRUE;`09`09`09/* plan a will work */ X`7D X X/* Keep (virtually) nothing in memory. */ X Xvoid Xplan_b(filename) Xchar *filename; X`7B X Reg3 FILE *ifp; X Reg1 int i = 0; X Reg2 int maxlen = 1; X Reg4 bool found_revision = (revision == Nullch); X X using_plan_a = FALSE; X if ((ifp = fopen(filename, "r")) == Nullfp) X`09fatal2("Can't open file %s\n", filename); X if ((tifd = creat(TMPINNAME, 0666)) < 0) X`09fatal2("Can't open file %s\n", TMPINNAME); X while (fgets(buf, sizeof buf, ifp) != Nullch) `7B X`09if (revision != Nullch && !found_revision && rev_in_string(buf)) X`09 found_revision = TRUE; X`09if ((i = strlen(buf)) > maxlen) X`09 maxlen = i;`09`09`09/* find longest line */ X `7D X if (revision != Nullch) `7B X`09if (!found_revision) `7B X`09 if (force) `7B X`09`09if (verbose) X`09`09 say2("\ XWarning: this file doesn't appear to be the %s version--patching anyway.\n", X`09`09`09revision); X`09 `7D X`09 else `7B X`09`09ask2("\ XThis file doesn't appear to be the %s version--patch anyway? `5Bn`5D ", X`09`09 revision); X`09`09if (*buf != 'y') X`09`09 fatal1("Aborted.\n"); X`09 `7D X`09`7D X`09else if (verbose) X`09 say2("Good. This file appears to be the %s version.\n", X`09`09revision); X `7D X Fseek(ifp, 0L, 0);`09`09/* rewind file */ X lines_per_buf = BUFFERSIZE / maxlen; X tireclen = maxlen; X tibuf`5B0`5D = malloc((MEM)(BUFFERSIZE + 1)); X tibuf`5B1`5D = malloc((MEM)(BUFFERSIZE + 1)); X if (tibuf`5B1`5D == Nullch) X`09fatal1("Can't seem to get enough memory.\n"); X for (i=1; ; i++) `7B X`09if (! (i % lines_per_buf))`09/* new block */ X`09 if (write(tifd, tibuf`5B0`5D, BUFFERSIZE) < BUFFERSIZE) X`09`09fatal1("patch: can't write temp file.\n"); X`09if (fgets(tibuf`5B0`5D + maxlen * (i%lines_per_buf), maxlen + 1, ifp) X`09 == Nullch) `7B X`09 input_lines = i - 1; X`09 if (i % lines_per_buf) X`09`09if (write(tifd, tibuf`5B0`5D, BUFFERSIZE) < BUFFERSIZE) X`09`09 fatal1("patch: can't write temp file.\n"); X`09 break; X`09`7D X `7D X Fclose(ifp); X Close(tifd); X if ((tifd = open(TMPINNAME, 0)) < 0) `7B X`09fatal2("Can't reopen file %s\n", TMPINNAME); X `7D X`7D X X/* Fetch a line from the input file, \n terminated, not necessarily \0. */ X Xchar * Xifetch(line,whichbuf) XReg1 LINENUM line; Xint whichbuf;`09`09`09`09/* ignored when file in memory */ X`7B X if (line < 1 `7C`7C line > input_lines) X`09return ""; X if (using_plan_a) X`09return i_ptr`5Bline`5D; X else `7B X`09LINENUM offline = line % lines_per_buf; X`09LINENUM baseline = line - offline; X X`09if (tiline`5B0`5D == baseline) X`09 whichbuf = 0; X`09else if (tiline`5B1`5D == baseline) X`09 whichbuf = 1; X`09else `7B X`09 tiline`5Bwhichbuf`5D = baseline; X#ifndef lint`09`09/* complains of long accuracy */ X`09 Lseek(tifd, (long)baseline / lines_per_buf * BUFFERSIZE, 0); X#endif X`09 if (read(tifd, tibuf`5Bwhichbuf`5D, BUFFERSIZE) < 0) X`09`09fatal2("Error reading tmp file %s.\n", TMPINNAME); X`09`7D X`09return tibuf`5Bwhichbuf`5D + (tireclen*offline); X `7D X`7D X X/* True if the string argument contains the revision number we want. */ X Xbool Xrev_in_string(string) Xchar *string; X`7B X Reg1 char *s; X Reg2 int patlen; X X if (revision == Nullch) X`09return TRUE; X patlen = strlen(revision); X for (s = string; *s; s++) `7B X`09if (isspace(*s) && strnEQ(s+1, revision, patlen) &&`20 X`09`09isspace(s`5Bpatlen+1`5D )) `7B X`09 return TRUE; X`09`7D X `7D X return FALSE; X`7D X $ CALL UNPACK [.SRC]INP.C;1 1092797036 $ create 'f' X/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $ X * X * $Log:`09inp.h,v $ X * Revision 2.0 86/09/17 15:37:25 lwall X * Baseline for netwide release. X *`20 X */ X XEXT LINENUM input_lines INIT(0);`09/* how long is input file in lines */ XEXT LINENUM last_frozen_line INIT(0);`09/* how many input lines have been */ X`09`09`09`09`09/* irretractibly output */ X Xbool rev_in_string(); Xvoid scan_input(); Xbool plan_a();`09`09`09/* returns false if insufficient memory */ Xvoid plan_b(); Xchar *ifetch(); X $ CALL UNPACK [.SRC]INP.H;1 1192057672 $ create 'f' X/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $ X * X * $Log:`09INTERN.h,v $ X * Revision 2.0 86/09/17 15:35:58 lwall X * Baseline for netwide release. X *`20 X */ X X#undef EXT X#define EXT X X#undef INIT X#define INIT(x) = x X X#define DOINIT $ CALL UNPACK [.SRC]INTERN.H;1 696126206 $ create 'f' Xchar rcsid`5B`5D = X`09"$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $"; X X/* patch - a program to apply diffs to original files X * X * Copyright 1986, Larry Wall X * X * This program may be copied as long as you don't try to make any X * money off of it, or pretend that you wrote it. X * X * $Log:`09patch.c,v $ X * Revision 2.0.1.4 87/02/16 14:00:04 lwall X * Short replacement caused spurious "Out of sync" message. X *`20 X * Revision 2.0.1.3 87/01/30 22:45:50 lwall X * Improved diagnostic on sync error. X * Moved do_ed_script() to pch.c. X *`20 X * Revision 2.0.1.2 86/11/21 09:39:15 lwall X * Fuzz factor caused offset of installed lines. X *`20 X * Revision 2.0.1.1 86/10/29 13:10:22 lwall X * Backwards search could terminate prematurely. X *`20 X * Revision 2.0 86/09/17 15:37:32 lwall X * Baseline for netwide release. X *`20 X * Revision 1.5 86/08/01 20:53:24 lwall X * Changed some %d's to %ld's. X * Linted. X *`20 X * Revision 1.4 86/08/01 19:17:29 lwall X * Fixes for machines that can't vararg. X * Added fuzz factor. X * Generalized -p. X * General cleanup. X *`20 X * 85/08/15 van%ucbmonet@berkeley X * Changes for 4.3bsd diff -c. X * X * Revision 1.3 85/03/26 15:07:43 lwall X * Frozen. X *`20 X * Revision 1.2.1.9 85/03/12 17:03:35 lwall X * Changed pfp->_file to fileno(pfp). X *`20 X * Revision 1.2.1.8 85/03/12 16:30:43 lwall X * Check i_ptr and i_womp to make sure they aren't null before freeing. X * Also allow ed output to be suppressed. X *`20 X * Revision 1.2.1.7 85/03/12 15:56:13 lwall X * Added -p option from jromine@uci-750a. X *`20 X * Revision 1.2.1.6 85/03/12 12:12:51 lwall X * Now checks for normalness of file to patch. X *`20 X * Revision 1.2.1.5 85/03/12 11:52:12 lwall X * Added -D (#ifdef) option from joe@fluke. X *`20 X * Revision 1.2.1.4 84/12/06 11:14:15 lwall X * Made smarter about SCCS subdirectories. X *`20 X * Revision 1.2.1.3 84/12/05 11:18:43 lwall X * Added -l switch to do loose string comparison. X *`20 X * Revision 1.2.1.2 84/12/04 09:47:13 lwall X * Failed hunk count not reset on multiple patch file. X *`20 X * Revision 1.2.1.1 84/12/04 09:42:37 lwall X * Branch for sdcrdcf changes. X *`20 X * Revision 1.2 84/11/29 13:29:51 lwall X * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed X * multiple calls to mktemp(). Will now work on machines that can only X * read 32767 chars. Added -R option for diffs with new and old swapped. X * Various cosmetic changes. X *`20 X * Revision 1.1 84/11/09 17:03:58 lwall X * Initial revision X *`20 X */ X X#include "INTERN.h" X#include "common.h" X#include "EXTERN.h" X#include "version.h" X#include "util.h" X#include "pch.h" X#include "inp.h" X X/* procedures */ X Xvoid reinitialize_almost_everything(); Xvoid get_some_switches(); XLINENUM locate_hunk(); Xvoid abort_hunk(); Xvoid apply_hunk(); Xvoid init_output(); Xvoid init_reject(); Xvoid copy_till(); Xvoid spew_output(); Xvoid dump_line(); Xbool patch_match(); Xbool similar(); Xvoid re_input(); Xvoid my_exit(); X X/* Apply a set of diffs as appropriate. */ X Xmain(argc,argv) Xint argc; Xchar **argv; X`7B X LINENUM where; X LINENUM newwhere; X LINENUM fuzz; X LINENUM mymaxfuzz; X int hunk = 0; X int failed = 0; X int i; X X#ifdef VMS X getredirection(&argc, &argv); X#endif X setbuf(stderr, serrbuf); X for (i = 0; i= 2) X`09fatal1("You may not change to a different patch file.\n"); X`7D X X/* Process switches and filenames up to next '+' or end of list. */ X Xvoid Xget_some_switches() X`7B X Reg1 char *s; X X rejname`5B0`5D = '\0'; X Argc_last = Argc; X Argv_last = Argv; X if (!Argc) X`09return; X for (Argc--,Argv++; Argc; Argc--,Argv++) `7B X`09s = Argv`5B0`5D; X`09if (strEQ(s, "+")) `7B X`09 return;`09`09`09/* + will be skipped by for loop */ X`09`7D X#ifdef VMS X`09if (*s == '<')`09`09`09/* Parse '= first_guess)`09/* do not try lines < 0 */ X`09max_neg_offset = first_guess - 1; X if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz V)) X`09return first_guess; X for (offset = 1; ; offset++) `7B X`09Reg5 bool check_after = (offset <= max_pos_offset); X`09Reg6 bool check_before = (offset <= max_neg_offset); X X`09if (check_after && patch_match(first_guess, offset, fuzz)) `7B X#ifdef DEBUGGING X`09 if (debug & 1) X`09`09say3("Offset changing from %ld to %ld\n", last_offset, offset); X#endif X`09 last_offset = offset; X`09 return first_guess+offset; X`09`7D X`09else if (check_before && patch_match(first_guess, -offset, fuzz)) `7B X#ifdef DEBUGGING X`09 if (debug & 1) X`09`09say3("Offset changing from %ld to %ld\n", last_offset, -offset); X#endif X`09 last_offset = -offset; X`09 return first_guess-offset; X`09`7D X`09else if (!check_before && !check_after) X`09 return Nulline; X `7D X`7D X X/* We did not find the pattern, dump out the hunk so they can handle it. */ X Xvoid Xabort_hunk() X`7B X Reg1 LINENUM i; X Reg2 LINENUM pat_end = pch_end(); X /* add in last_offset to guess the same as the previous successful hunk V */ X LINENUM oldfirst = pch_first() + last_offset; X LINENUM newfirst = pch_newfirst() + last_offset; X LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; X LINENUM newlast = newfirst + pch_repl_lines() - 1; X char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : ""); X char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----"); X X fprintf(rejfp, "***************\n"); X for (i=0; i<=pat_end; i++) `7B X`09switch (pch_char(i)) `7B X`09case '*': X`09 if (oldlast < oldfirst) X`09`09fprintf(rejfp, "*** 0%s\n", stars); X`09 else if (oldlast == oldfirst) X`09`09fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); X`09 else X`09`09fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars); X`09 break; X`09case '=': X`09 if (newlast < newfirst) X`09`09fprintf(rejfp, "--- 0%s\n", minuses); X`09 else if (newlast == newfirst) X`09`09fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); X`09 else X`09`09fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses); X`09 break; X`09case '\n': X`09 fprintf(rejfp, "%s", pfetch(i)); X`09 break; X`09case ' ': case '-': case '+': case '!': X`09 fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); X`09 break; X`09default: X`09 say1("Fatal internal error in abort_hunk().\n");`20 X`09 abort(); X`09`7D X `7D X`7D X X/* We found where to apply it (we hope), so do it. */ X Xvoid Xapply_hunk(where) XLINENUM where; X`7B X Reg1 LINENUM old = 1; X Reg2 LINENUM lastline = pch_ptrn_lines(); X Reg3 LINENUM new = lastline+1; X#define OUTSIDE 0 X#define IN_IFNDEF 1 X#define IN_IFDEF 2 X#define IN_ELSE 3 X Reg4 int def_state = OUTSIDE; X Reg5 bool R_do_defines = do_defines; X Reg6 LINENUM pat_end = pch_end(); X X where--; X while (pch_char(new) == '=' `7C`7C pch_char(new) == '\n') X`09new++; X `20 X while (old <= lastline) `7B X`09if (pch_char(old) == '-') `7B X`09 copy_till(where + old - 1); X`09 if (R_do_defines) `7B X`09`09if (def_state == OUTSIDE) `7B X`09`09 fputs(not_defined, ofp); X`09`09 def_state = IN_IFNDEF; X`09`09`7D X`09`09else if (def_state == IN_IFDEF) `7B X`09`09 fputs(else_defined, ofp); X`09`09 def_state = IN_ELSE; X`09`09`7D X`09`09fputs(pfetch(old), ofp); X`09 `7D X`09 last_frozen_line++; X`09 old++; X`09`7D X`09else if (new > pat_end) X`09 break; X`09else if (pch_char(new) == '+') `7B X`09 copy_till(where + old - 1); X`09 if (R_do_defines) `7B X`09`09if (def_state == IN_IFNDEF) `7B X`09`09 fputs(else_defined, ofp); X`09`09 def_state = IN_ELSE; X`09`09`7D X`09`09else if (def_state == OUTSIDE) `7B X`09`09 fputs(if_defined, ofp); X`09`09 def_state = IN_IFDEF; X`09`09`7D X`09 `7D X`09 fputs(pfetch(new), ofp); X`09 new++; X`09`7D X`09else `7B X`09 if (pch_char(new) != pch_char(old)) `7B X`09`09say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, V maybe?\n", X`09`09 pch_hunk_beg() + old, X`09`09 pch_hunk_beg() + new); X#ifdef DEBUGGING X`09`09say3("oldchar = '%c', newchar = '%c'\n", X`09`09 pch_char(old), pch_char(new)); X#endif X`09`09my_exit(1); X`09 `7D X`09 if (pch_char(new) == '!') `7B X`09`09copy_till(where + old - 1); X`09`09if (R_do_defines) `7B X`09`09 fputs(not_defined, ofp); X`09`09 def_state = IN_IFNDEF; X`09`09`7D X`09`09while (pch_char(old) == '!') `7B X`09`09 if (R_do_defines) `7B X`09`09`09fputs(pfetch(old), ofp); X`09`09 `7D X`09`09 last_frozen_line++; X`09`09 old++; X`09`09`7D X`09`09if (R_do_defines) `7B X`09`09 fputs(else_defined, ofp); X`09`09 def_state = IN_ELSE; X`09`09`7D X`09`09while (pch_char(new) == '!') `7B X`09`09 fputs(pfetch(new), ofp); X`09`09 new++; X`09`09`7D X`09`09if (R_do_defines) `7B X`09`09 fputs(end_defined, ofp); X`09`09 def_state = OUTSIDE; X`09`09`7D X`09 `7D X`09 else `7B X`09`09assert(pch_char(new) == ' '); X`09`09old++; X`09`09new++; X`09 `7D X`09`7D X `7D X if (new <= pat_end && pch_char(new) == '+') `7B X`09copy_till(where + old - 1); X`09if (R_do_defines) `7B X`09 if (def_state == OUTSIDE) `7B X`09 `09fputs(if_defined, ofp); X`09`09def_state = IN_IFDEF; X`09 `7D X`09 else if (def_state == IN_IFNDEF) `7B X`09`09fputs(else_defined, ofp); X`09`09def_state = IN_ELSE; X`09 `7D X`09`7D X`09while (new <= pat_end && pch_char(new) == '+') `7B X`09 fputs(pfetch(new), ofp); X`09 new++; X`09`7D X `7D X if (R_do_defines && def_state != OUTSIDE) `7B X`09fputs(end_defined, ofp); X `7D X`7D X X/* Open the new file. */ X Xvoid Xinit_output(name) Xchar *name; X`7B X ofp = fopen(name, "w"); X if (ofp == Nullfp) X`09fatal2("patch: can't create %s.\n", name); X`7D X X/* Open a file to put hunks we can't locate. */ X Xvoid Xinit_reject(name) Xchar *name; X`7B X rejfp = fopen(name, "w"); X if (rejfp == Nullfp) X`09fatal2("patch: can't create %s.\n", name); X`7D +-+-+-+-+-+-+-+- END OF PART 9 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 10 -+-+-+-+-+-+-+-+ X X/* Copy input file to output, up to wherever hunk is to be applied. */ X Xvoid Xcopy_till(lastline) XReg1 LINENUM lastline; X`7B X Reg2 LINENUM R_last_frozen_line = last_frozen_line; X X if (R_last_frozen_line > lastline) X`09say1("patch: misordered hunks! output will be garbled.\n"); X while (R_last_frozen_line < lastline) `7B X`09dump_line(++R_last_frozen_line); X `7D X last_frozen_line = R_last_frozen_line; X`7D X X/* Finish copying the input file to the output file. */ X Xvoid Xspew_output() X`7B X#ifdef DEBUGGING X if (debug & 256) X`09say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line); X#endif X if (input_lines) X`09copy_till(input_lines);`09`09/* dump remainder of file */ X Fclose(ofp); X ofp = Nullfp; X`7D X X/* Copy one line from input to output. */ X Xvoid Xdump_line(line) XLINENUM line; X`7B X Reg1 char *s; X Reg2 char R_newline = '\n'; X X /* Note: string is not null terminated. */ X for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ; X`7D X X/* Does the patch pattern match at line base+offset? */ X Xbool Xpatch_match(base, offset, fuzz) XLINENUM base; XLINENUM offset; XLINENUM fuzz; X`7B X Reg1 LINENUM pline = 1 + fuzz; X Reg2 LINENUM iline; X Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz; X X for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) `7B X`09if (canonicalize) `7B X`09 if (!similar(ifetch(iline, (offset >= 0)), X`09`09`09 pfetch(pline), X`09`09`09 pch_line_len(pline) )) X`09`09return FALSE; X`09`7D X`09else if (strnNE(ifetch(iline, (offset >= 0)), X`09`09 pfetch(pline), X`09`09 pch_line_len(pline) )) X`09 return FALSE; X `7D X return TRUE; X`7D X X/* Do two lines match with canonicalized white space? */ X Xbool Xsimilar(a,b,len) XReg1 char *a; XReg2 char *b; XReg3 int len; X`7B X while (len) `7B X`09if (isspace(*b)) `7B`09`09/* whitespace (or \n) to match? */ X`09 if (!isspace(*a))`09`09/* no corresponding whitespace? */ X`09`09return FALSE; X`09 while (len && isspace(*b) && *b != '\n') X`09`09b++,len--;`09`09/* skip pattern whitespace */ X`09 while (isspace(*a) && *a != '\n') X`09`09a++;`09`09`09/* skip target whitespace */ X`09 if (*a == '\n' `7C`7C *b == '\n') X`09`09return (*a == *b);`09/* should end in sync */ X`09`7D X`09else if (*a++ != *b++)`09`09/* match non-whitespace chars */ X`09 return FALSE; X`09else X`09 len--;`09`09`09/* probably not necessary */ X `7D X return TRUE;`09`09`09/* actually, this is not reached */ X`09`09`09`09`09/* since there is always a \n */ X`7D X X/* Exit with cleanup. */ X Xvoid Xmy_exit(status) Xint status; X`7B X while (unlink(TMPINNAME) >= 0); X if (!toutkeep) `7B X`09while (unlink(TMPOUTNAME) >= 0); X `7D X if (!trejkeep) `7B X`09while (unlink(TMPREJNAME) >= 0); X `7D X while (unlink(TMPPATNAME) >= 0); X exit(status); X`7D $ CALL UNPACK [.SRC]PATCH.C;1 728881360 $ create 'f' X#define PATCHLEVEL 9 $ CALL UNPACK [.SRC]PATCHLEVEL.H;1 1781615383 $ create 'f' X/* $Header: pch.c,v 2.0.1.6 87/06/04 16:18:13 lwall Exp $ X * X * $Log:`09pch.c,v $ X * Revision 2.0.1.6 87/06/04 16:18:13 lwall X * pch_swap didn't swap p_bfake and p_efake. X *`20 X * Revision 2.0.1.5 87/01/30 22:47:42 lwall X * Improved responses to mangled patches. X *`20 X * Revision 2.0.1.4 87/01/05 16:59:53 lwall X * New-style context diffs caused double call to free(). X *`20 X * Revision 2.0.1.3 86/11/14 10:08:33 lwall X * Fixed problem where a long pattern wouldn't grow the hunk. X * Also restored p_input_line when backtracking so error messages are right. X *`20 X * Revision 2.0.1.2 86/11/03 17:49:52 lwall X * New-style delete triggers spurious assertion error. X *`20 X * Revision 2.0.1.1 86/10/29 15:52:08 lwall X * Could falsely report new-style context diff. X *`20 X * Revision 2.0 86/09/17 15:39:37 lwall X * Baseline for netwide release. X *`20 X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "INTERN.h" X#include "pch.h" X X/* Patch (diff listing) abstract type. */ X Xstatic long p_filesize;`09`09`09/* size of the patch file */ Xstatic LINENUM p_first;`09`09`09/* 1st line number */ Xstatic LINENUM p_newfirst;`09`09/* 1st line number of replacement */ Xstatic LINENUM p_ptrn_lines;`09`09/* # lines in pattern */ Xstatic LINENUM p_repl_lines;`09`09/* # lines in replacement text */ Xstatic LINENUM p_end = -1;`09`09/* last line in hunk */ Xstatic LINENUM p_max;`09`09`09/* max allowed value of p_end */ Xstatic LINENUM p_context = 3;`09`09/* # of context lines */ Xstatic LINENUM p_input_line = 0;`09/* current line # from patch file */ Xstatic char **p_line = Null(char**);`09/* the text of the hunk */ Xstatic short *p_len = Null(short*);`09/* length of each line */ Xstatic char *p_char = Nullch;`09`09/* +, -, and ! */ Xstatic int hunkmax = INITHUNKMAX;`09/* size of above arrays to begin with */ Xstatic int p_indent;`09`09`09/* indent to patch */ Xstatic LINENUM p_base;`09`09`09/* where to intuit this time */ Xstatic LINENUM p_bline;`09`09`09/* line # of p_base */ Xstatic LINENUM p_start;`09`09`09/* where intuit found a patch */ Xstatic LINENUM p_sline;`09`09`09/* and the line number for it */ Xstatic LINENUM p_hunk_beg;`09`09/* line number of current hunk */ Xstatic LINENUM p_efake = -1;`09`09/* end of faked up lines--don't free */ Xstatic LINENUM p_bfake = -1;`09`09/* beg of faked up lines */ X X/* Prepare to look for the next patch in the patch file. */ X Xvoid Xre_patch() X`7B X p_first = Nulline; X p_newfirst = Nulline; X p_ptrn_lines = Nulline; X p_repl_lines = Nulline; X p_end = (LINENUM)-1; X p_max = Nulline; X p_indent = 0; X`7D X X/* Open the patch file at the beginning of time. */ X Xvoid Xopen_patch_file(filename) Xchar *filename; X`7B X if (filename == Nullch `7C`7C !*filename `7C`7C strEQ(filename, "-")) `7 VB X`09pfp = fopen(TMPPATNAME, "w"); X`09if (pfp == Nullfp) X`09 fatal2("patch: can't create %s.\n", TMPPATNAME); X`09while (fgets(buf, sizeof buf, stdin) != Nullch) X`09 fputs(buf, pfp); X`09Fclose(pfp); X`09filename = TMPPATNAME; X `7D X pfp = fopen(filename, "r"); X if (pfp == Nullfp) X`09fatal2("patch file %s not found\n", filename); X Fstat(fileno(pfp), &filestat); X p_filesize = filestat.st_size; X next_intuit_at(0L,1L);`09`09`09/* start at the beginning */ X set_hunkmax(); X`7D X X/* Make sure our dynamically realloced tables are malloced to begin with. */ X Xvoid Xset_hunkmax() X`7B X#ifndef lint X if (p_line == Null(char**)) X`09p_line = (char**) malloc((MEM)hunkmax * sizeof(char *)); X if (p_len == Null(short*)) X`09p_len = (short*) malloc((MEM)hunkmax * sizeof(short)); X#endif X if (p_char == Nullch) X`09p_char = (char*) malloc((MEM)hunkmax * sizeof(char)); X`7D X X/* Enlarge the arrays containing the current hunk of patch. */ X Xvoid Xgrow_hunkmax() X`7B X hunkmax *= 2; X /*`20 X * Note that on most systems, only the p_line array ever gets fresh memo Vry X * since p_len can move into p_line's old space, and p_char can move int Vo X * p_len's old space. Not on PDP-11's however. But it doesn't matter. X */ X assert(p_line != Null(char**) && p_len != Null(short*) && p_char != Null Vch); X#ifndef lint X p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *)); X p_len = (short*) realloc((char*)p_len, (MEM)hunkmax * sizeof(short)); X p_char = (char*) realloc((char*)p_char, (MEM)hunkmax * sizeof(char)); X#endif X if (p_line != Null(char**) && p_len != Null(short*) && p_char != Nullch) X`09return; X if (!using_plan_a) X`09fatal1("patch: out of memory (grow_hunkmax)\n"); X out_of_mem = TRUE;`09`09/* whatever is null will be allocated again */ X`09`09`09`09/* from within plan_a(), of all places */ X`7D X X/* True if the remainder of the patch file contains a diff of some sort. */ X Xbool Xthere_is_another_patch() X`7B X if (p_base != 0L && p_base >= p_filesize) `7B X`09if (verbose) X`09 say1("done\n"); X`09return FALSE; X `7D X if (verbose) X`09say1("Hmm..."); X diff_type = intuit_diff_type(); X if (!diff_type) `7B X`09if (p_base != 0L) `7B X`09 if (verbose) X`09`09say1(" Ignoring the trailing garbage.\ndone\n"); X`09`7D X`09else X`09 say1(" I can't seem to find a patch in there anywhere.\n"); X`09return FALSE; X `7D X if (verbose) X`09say3(" %sooks like %s to me...\n", X`09 (p_base == 0L ? "L" : "The next patch l"), X`09 diff_type == CONTEXT_DIFF ? "a context diff" : X`09 diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : X`09 diff_type == NORMAL_DIFF ? "a normal diff" : X`09 "an ed script" ); X if (p_indent && verbose) X`09say3("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); X skip_to(p_start,p_sline); X while (filearg`5B0`5D == Nullch) `7B X`09if (force) `7B X`09 say1("No file to patch. Skipping...\n"); X`09 filearg`5B0`5D = savestr(bestguess); X`09 return TRUE; X`09`7D X`09ask1("File to patch: "); X`09if (*buf != '\n') `7B X`09 if (bestguess) X`09`09free(bestguess); X`09 bestguess = savestr(buf); X`09 filearg`5B0`5D = fetchname(buf, 0, FALSE); X`09`7D X`09if (filearg`5B0`5D == Nullch) `7B X`09 ask1("No file found--skip this patch? `5Bn`5D "); X`09 if (*buf != 'y') `7B X`09`09continue; X`09 `7D X`09 if (verbose) X`09`09say1("Skipping patch...\n"); X`09 filearg`5B0`5D = fetchname(bestguess, 0, TRUE); X`09 skip_rest_of_patch = TRUE; X`09 return TRUE; X`09`7D X `7D X return TRUE; X`7D X X/* Determine what kind of diff is in the remaining part of the patch file. * V/ X Xint Xintuit_diff_type() X`7B X Reg4 long this_line = 0; X Reg5 long previous_line; X Reg6 long first_command_line = -1; X long fcl_line; X Reg7 bool last_line_was_command = FALSE; X Reg8 bool this_is_a_command = FALSE; X Reg9 bool stars_last_line = FALSE; X Reg10 bool stars_this_line = FALSE; X Reg3 int indent; X Reg1 char *s; X Reg2 char *t; X char *indtmp = Nullch; X char *oldtmp = Nullch; X char *newtmp = Nullch; X char *indname = Nullch; X char *oldname = Nullch; X char *newname = Nullch; X Reg11 int retval; X bool no_filearg = (filearg`5B0`5D == Nullch); X X ok_to_create_file = FALSE; X Fseek(pfp, p_base, 0); X p_input_line = p_bline - 1; X for (;;) `7B X`09previous_line = this_line; X`09last_line_was_command = this_is_a_command; X`09stars_last_line = stars_this_line; X`09this_line = ftell(pfp); X`09indent = 0; X`09p_input_line++; X`09if (fgets(buf, sizeof buf, pfp) == Nullch) `7B X`09 if (first_command_line >= 0L) `7B X`09`09`09`09`09/* nothing but deletes!? */ X`09`09p_start = first_command_line; X`09`09p_sline = fcl_line; X`09`09retval = ED_DIFF; X`09`09goto scan_exit; X`09 `7D X`09 else `7B X`09`09p_start = this_line; X`09`09p_sline = p_input_line; X`09`09retval = 0; X`09`09goto scan_exit; X`09 `7D X`09`7D X`09for (s = buf; *s == ' ' `7C`7C *s == '\t'; s++) `7B X`09 if (*s == '\t') X`09`09indent += 8 - (indent % 8); X`09 else X`09`09indent++; X`09`7D X`09for (t=s; isdigit(*t) `7C`7C *t == ','; t++) ;`20 X`09this_is_a_command = (isdigit(*s) && X`09 (*t == 'd' `7C`7C *t == 'c' `7C`7C *t == 'a') ); X`09if (first_command_line < 0L && this_is_a_command) `7B`20 X`09 first_command_line = this_line; X`09 fcl_line = p_input_line; X`09 p_indent = indent;`09`09/* assume this for now */ X`09`7D X`09if (!stars_last_line && strnEQ(s, "*** ", 4)) X`09 oldtmp = savestr(s+4); X`09else if (strnEQ(s, "--- ", 4)) X`09 newtmp = savestr(s+4); X`09else if (strnEQ(s, "Index:", 6)) X`09 indtmp = savestr(s+6); X`09else if (strnEQ(s, "Prereq:", 7)) `7B X`09 for (t=s+7; isspace(*t); t++) ; X`09 revision = savestr(t); X`09 for (t=revision; *t && !isspace(*t); t++) ; X`09 *t = '\0'; X`09 if (!*revision) `7B X`09`09free(revision); X`09`09revision = Nullch; X`09 `7D X`09`7D X`09if ((!diff_type `7C`7C diff_type == ED_DIFF) && X`09 first_command_line >= 0L && X`09 strEQ(s, ".\n") ) `7B X`09 p_indent = indent; X`09 p_start = first_command_line; X`09 p_sline = fcl_line; X`09 retval = ED_DIFF; X`09 goto scan_exit; X`09`7D X`09stars_this_line = strnEQ(s, "********", 8); X`09if ((!diff_type `7C`7C diff_type == CONTEXT_DIFF) && stars_last_line && X`09`09 strnEQ(s, "*** ", 4)) `7B X`09 if (!atol(s+4)) X`09`09ok_to_create_file = TRUE; X`09 /* if this is a new context diff the character just before */ X`09 /* the newline is a '*'. */ X`09 while (*s != '\n') X`09`09s++; X`09 p_indent = indent; X`09 p_start = previous_line; X`09 p_sline = p_input_line - 1; X`09 retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); X`09 goto scan_exit; X`09`7D X`09if ((!diff_type `7C`7C diff_type == NORMAL_DIFF) &&`20 X`09 last_line_was_command && X`09 (strnEQ(s, "< ", 2) `7C`7C strnEQ(s, "> ", 2)) ) `7B X`09 p_start = previous_line; X`09 p_sline = p_input_line - 1; X`09 p_indent = indent; X`09 retval = NORMAL_DIFF; X`09 goto scan_exit; X`09`7D X `7D X scan_exit: X if (no_filearg) `7B X`09if (indtmp != Nullch) X`09 indname = fetchname(indtmp, strippath, ok_to_create_file); X`09if (oldtmp != Nullch) X`09 oldname = fetchname(oldtmp, strippath, ok_to_create_file); X`09if (newtmp != Nullch) X`09 newname = fetchname(newtmp, strippath, ok_to_create_file); X`09if (oldname && newname) `7B X`09 if (strlen(oldname) < strlen(newname)) X`09`09filearg`5B0`5D = savestr(oldname); X`09 else X`09`09filearg`5B0`5D = savestr(newname); X`09`7D X`09else if (oldname) X`09 filearg`5B0`5D = savestr(oldname); X`09else if (newname) X`09 filearg`5B0`5D = savestr(newname); X`09else if (indname) X`09 filearg`5B0`5D = savestr(indname); X `7D X if (bestguess) `7B X`09free(bestguess); X`09bestguess = Nullch; X `7D X if (filearg`5B0`5D != Nullch) X`09bestguess = savestr(filearg`5B0`5D); X else if (indtmp != Nullch) X`09bestguess = fetchname(indtmp, strippath, TRUE); X else `7B X`09if (oldtmp != Nullch) X`09 oldname = fetchname(oldtmp, strippath, TRUE); X`09if (newtmp != Nullch) X`09 newname = fetchname(newtmp, strippath, TRUE); X`09if (oldname && newname) `7B +-+-+-+-+-+-+-+- END OF PART 10 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 11 -+-+-+-+-+-+-+-+ X`09 if (strlen(oldname) < strlen(newname)) X`09`09bestguess = savestr(oldname); X`09 else X`09`09bestguess = savestr(newname); X`09`7D X`09else if (oldname) X`09 bestguess = savestr(oldname); X`09else if (newname) X`09 bestguess = savestr(newname); X `7D X if (indtmp != Nullch) X`09free(indtmp); X if (oldtmp != Nullch) X`09free(oldtmp); X if (newtmp != Nullch) X`09free(newtmp); X if (indname != Nullch) X`09free(indname); X if (oldname != Nullch) X`09free(oldname); X if (newname != Nullch) X`09free(newname); X return retval; X`7D X X/* Remember where this patch ends so we know where to start up again. */ X Xvoid Xnext_intuit_at(file_pos,file_line) Xlong file_pos; Xlong file_line; X`7B X p_base = file_pos; X p_bline = file_line; X`7D X X/* Basically a verbose fseek() to the actual diff listing. */ X Xvoid Xskip_to(file_pos,file_line) Xlong file_pos; Xlong file_line; X`7B X char *ret; X X assert(p_base <= file_pos); X if (verbose && p_base < file_pos) `7B X`09Fseek(pfp, p_base, 0); X`09say1("The text leading up to this was:\n--------------------------\n"); X`09while (ftell(pfp) < file_pos) `7B X`09 ret = fgets(buf, sizeof buf, pfp); X`09 assert(ret != Nullch); X`09 say2("`7C%s", buf); X`09`7D X`09say1("--------------------------\n"); X `7D X else X`09Fseek(pfp, file_pos, 0); X p_input_line = file_line - 1; X`7D X X/* True if there is more of the current diff listing to process. */ X Xbool Xanother_hunk() X`7B X Reg1 char *s; X Reg8 char *ret; X Reg2 int context = 0; X X while (p_end >= 0) `7B X`09if (p_end == p_efake) X`09 p_end = p_bfake;`09`09/* don't free twice */ X`09else X`09 free(p_line`5Bp_end`5D); X`09p_end--; X `7D X assert(p_end == -1); X p_efake = -1; X X p_max = hunkmax;`09`09`09/* gets reduced when --- found */ X if (diff_type == CONTEXT_DIFF `7C`7C diff_type == NEW_CONTEXT_DIFF) `7B X`09long line_beginning = ftell(pfp); X`09`09`09`09`09/* file pos of the current line */ X`09LINENUM repl_beginning = 0;`09/* index of --- line */ X`09Reg4 LINENUM fillcnt = 0;`09/* #lines of missing ptrn or repl */ X`09Reg5 LINENUM fillsrc;`09`09/* index of first line to copy */ X`09Reg6 LINENUM filldst;`09`09/* index of first missing line */ X`09bool ptrn_spaces_eaten = FALSE;`09/* ptrn was slightly misformed */ X`09Reg9 bool repl_could_be_missing = TRUE; X`09`09`09`09`09/* no + or ! lines in this hunk */ X`09bool repl_missing = FALSE;`09/* we are now backtracking */ X`09long repl_backtrack_position = 0; X`09`09`09`09`09/* file pos of first repl line */ X`09LINENUM repl_patch_line;`09/* input line number for same */ X`09Reg7 LINENUM ptrn_copiable = 0; X`09`09`09`09`09/* # of copiable lines in ptrn */ X X`09ret = pgets(buf, sizeof buf, pfp); X`09p_input_line++; X`09if (ret == Nullch `7C`7C strnNE(buf, "********", 8)) `7B X`09 next_intuit_at(line_beginning,p_input_line); X`09 return FALSE; X`09`7D X`09p_context = 100; X`09p_hunk_beg = p_input_line + 1; X`09while (p_end < p_max) `7B X`09 line_beginning = ftell(pfp); X`09 ret = pgets(buf, sizeof buf, pfp); X`09 p_input_line++; X`09 if (ret == Nullch) `7B X`09`09if (p_max - p_end < 4) X`09`09 Strcpy(buf, " \n"); /* assume blank lines got chopped */ X`09`09else `7B X`09`09 if (repl_beginning && repl_could_be_missing) `7B X`09`09`09repl_missing = TRUE; X`09`09`09goto hunk_done; X`09`09 `7D X`09`09 fatal1("Unexpected end of file in patch.\n"); X`09`09`7D X`09 `7D X`09 p_end++; X`09 assert(p_end < hunkmax); X`09 p_char`5Bp_end`5D = *buf; X`09 p_line`5Bp_end`5D = Nullch; X`09 switch (*buf) `7B X`09 case '*': X`09`09if (strnEQ(buf, "********", 8)) `7B X`09`09 if (repl_beginning && repl_could_be_missing) `7B X`09`09`09repl_missing = TRUE; X`09`09`09goto hunk_done; X`09`09 `7D X`09`09 else X`09`09`09fatal2("Unexpected end of hunk at line %ld.\n", X`09`09`09 p_input_line); X`09`09`7D X`09`09if (p_end != 0) `7B X`09`09 if (repl_beginning && repl_could_be_missing) `7B X`09`09`09repl_missing = TRUE; X`09`09`09goto hunk_done; X`09`09 `7D X`09`09 fatal3("Unexpected *** at line %ld: %s", p_input_line, buf); X`09`09`7D X`09`09context = 0; X`09`09p_line`5Bp_end`5D = savestr(buf); X`09`09if (out_of_mem) `7B X`09`09 p_end--; X`09`09 return FALSE; X`09`09`7D X`09`09for (s=buf; *s && !isdigit(*s); s++) ; X`09`09if (!*s) X`09`09 goto malformed; X`09`09p_first = (LINENUM) atol(s); X`09`09while (isdigit(*s)) s++; X`09`09if (*s == ',') `7B X`09`09 for (; *s && !isdigit(*s); s++) ; X`09`09 if (!*s) X`09`09`09goto malformed; X`09`09 p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; X`09`09`7D X`09`09else if (p_first) X`09`09 p_ptrn_lines = 1; X`09`09else `7B X`09`09 p_ptrn_lines = 0; X`09`09 p_first = 1; X`09`09`7D X`09`09p_max = p_ptrn_lines + 6;`09/* we need this much at least */ X`09`09while (p_max >= hunkmax) X`09`09 grow_hunkmax(); X`09`09p_max = hunkmax; X`09`09break; X`09 case '-': X`09`09if (buf`5B1`5D == '-') `7B X`09`09 if (repl_beginning `7C`7C X`09`09`09(p_end != p_ptrn_lines + 1 + (p_char`5Bp_end-1`5D == '\n'))) X`09`09 `7B X`09`09`09if (p_end == 1) `7B X`09`09`09 /* `60old' lines were omitted - set up to fill */ X`09`09`09 /* them in from 'new' context lines. */ X`09`09`09 p_end = p_ptrn_lines + 1; X`09`09`09 fillsrc = p_end + 1; X`09`09`09 filldst = 1; X`09`09`09 fillcnt = p_ptrn_lines; X`09`09`09`7D X`09`09`09else `7B X`09`09`09 if (repl_beginning) `7B X`09`09`09`09if (repl_could_be_missing)`7B X`09`09`09`09 repl_missing = TRUE; X`09`09`09`09 goto hunk_done; X`09`09`09`09`7D X`09`09`09`09fatal3( X"Duplicate \"---\" at line %ld--check line numbers at line %ld.\n", X`09`09`09`09 p_input_line, p_hunk_beg + repl_beginning); X`09`09`09 `7D X`09`09`09 else `7B X`09`09`09`09fatal4( X"%s \"---\" at line %ld--check line numbers at line %ld.\n", X`09`09`09`09 (p_end <= p_ptrn_lines X`09`09`09`09`09? "Premature" X`09`09`09`09`09: "Overdue" ), X`09`09`09`09 p_input_line, p_hunk_beg); X`09`09`09 `7D X`09`09`09`7D X`09`09 `7D X`09`09 repl_beginning = p_end; X`09`09 repl_backtrack_position = ftell(pfp); X`09`09 repl_patch_line = p_input_line; X`09`09 p_line`5Bp_end`5D = savestr(buf); X`09`09 if (out_of_mem) `7B X`09`09`09p_end--; X`09`09`09return FALSE; X`09`09 `7D X`09`09 p_char`5Bp_end`5D = '='; X`09`09 for (s=buf; *s && !isdigit(*s); s++) ; X`09`09 if (!*s) X`09`09`09goto malformed; X`09`09 p_newfirst = (LINENUM) atol(s); X`09`09 while (isdigit(*s)) s++; X`09`09 if (*s == ',') `7B X`09`09`09for (; *s && !isdigit(*s); s++) ; X`09`09`09if (!*s) X`09`09`09 goto malformed; X`09`09`09p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1; X`09`09 `7D X`09`09 else if (p_newfirst) X`09`09`09p_repl_lines = 1; X`09`09 else `7B X`09`09`09p_repl_lines = 0; X`09`09`09p_newfirst = 1; X`09`09 `7D X`09`09 p_max = p_repl_lines + p_end; X`09`09 if (p_max > MAXHUNKSIZE) X`09`09`09fatal4("Hunk too large (%ld lines) at line %ld: %s", X`09`09`09 p_max, p_input_line, buf); X`09`09 while (p_max >= hunkmax) X`09`09`09grow_hunkmax(); X`09`09 if (p_repl_lines != ptrn_copiable) X`09`09`09repl_could_be_missing = FALSE; X`09`09 break; X`09`09`7D X`09`09goto change_line; X`09 case '+': case '!': X`09`09repl_could_be_missing = FALSE; X`09 change_line: X`09`09if (!isspace(buf`5B1`5D) && buf`5B1`5D != '>' && buf`5B1`5D != '<' && X`09`09 repl_beginning && repl_could_be_missing) `7B X`09`09 repl_missing = TRUE; X`09`09 goto hunk_done; X`09`09`7D X`09`09if (context > 0) `7B X`09`09 if (context < p_context) X`09`09`09p_context = context; X`09`09 context = -1000; X`09`09`7D X`09`09p_line`5Bp_end`5D = savestr(buf+2); X`09`09if (out_of_mem) `7B X`09`09 p_end--; X`09`09 return FALSE; X`09`09`7D X`09`09break; X`09 case '\t': case '\n':`09/* assume the 2 spaces got eaten */ X`09`09if (repl_beginning && repl_could_be_missing && X`09`09 (!ptrn_spaces_eaten `7C`7C diff_type == NEW_CONTEXT_DIFF) ) `7B X`09`09 repl_missing = TRUE; X`09`09 goto hunk_done; X`09`09`7D X`09`09p_line`5Bp_end`5D = savestr(buf); X`09`09if (out_of_mem) `7B X`09`09 p_end--; X`09`09 return FALSE; X`09`09`7D X`09`09if (p_end != p_ptrn_lines + 1) `7B X`09`09 ptrn_spaces_eaten `7C= (repl_beginning != 0); X`09`09 context++; X`09`09 if (!repl_beginning) X`09`09`09ptrn_copiable++; X`09`09 p_char`5Bp_end`5D = ' '; X`09`09`7D X`09`09break; X`09 case ' ': X`09`09if (!isspace(buf`5B1`5D) && X`09`09 repl_beginning && repl_could_be_missing) `7B X`09`09 repl_missing = TRUE; X`09`09 goto hunk_done; X`09`09`7D X`09`09context++; X`09`09if (!repl_beginning) X`09`09 ptrn_copiable++; X`09`09p_line`5Bp_end`5D = savestr(buf+2); X`09`09if (out_of_mem) `7B X`09`09 p_end--; X`09`09 return FALSE; X`09`09`7D X`09`09break; X`09 default: X`09`09if (repl_beginning && repl_could_be_missing) `7B X`09`09 repl_missing = TRUE; X`09`09 goto hunk_done; X`09`09`7D X`09`09goto malformed; X`09 `7D X`09 /* set up p_len for strncmp() so we don't have to */ X`09 /* assume null termination */ X`09 if (p_line`5Bp_end`5D) X`09`09p_len`5Bp_end`5D = strlen(p_line`5Bp_end`5D); X`09 else X`09`09p_len`5Bp_end`5D = 0; X`09`7D X`09 X hunk_done: X`09if (p_end >=0 && !repl_beginning) X`09 fatal2("No --- found in patch at line %ld\n", pch_hunk_beg()); X X`09if (repl_missing) `7B X`09 `20 X`09 /* reset state back to just after --- */ X`09 p_input_line = repl_patch_line; X`09 for (p_end--; p_end > repl_beginning; p_end--) X`09`09free(p_line`5Bp_end`5D); X`09 Fseek(pfp, repl_backtrack_position, 0); X`09 `20 X`09 /* redundant 'new' context lines were omitted - set */ X`09 /* up to fill them in from the old file context */ X`09 fillsrc = 1; X`09 filldst = repl_beginning+1; X`09 fillcnt = p_repl_lines; X`09 p_end = p_max; X`09`7D X X`09if (diff_type == CONTEXT_DIFF && X`09 (fillcnt `7C`7C (p_first > 1 && ptrn_copiable > 2*p_context)) ) `7B X`09 if (verbose) X`09`09say1("\ X(Fascinating--this is really a new-style context diff but without the tellta Vle\n\ Xextra asterisks on the *** line that usually indicate the new style...)\n"); X`09 diff_type = NEW_CONTEXT_DIFF; X`09`7D X`09 X`09/* if there were omitted context lines, fill them in now */ X`09if (fillcnt) `7B X`09 p_bfake = filldst;`09`09/* remember where not to free() */ X`09 p_efake = filldst + fillcnt - 1; X`09 while (fillcnt-- > 0) `7B X`09`09while (fillsrc <= p_end && p_char`5Bfillsrc`5D != ' ') X`09`09 fillsrc++; X`09`09if (fillsrc > p_end) X`09`09 fatal2("Replacement text or line numbers mangled in hunk at line % Vld\n", X`09`09`09p_hunk_beg); X`09`09p_line`5Bfilldst`5D = p_line`5Bfillsrc`5D; X`09`09p_char`5Bfilldst`5D = p_char`5Bfillsrc`5D; X`09`09p_len`5Bfilldst`5D = p_len`5Bfillsrc`5D; X`09`09fillsrc++; filldst++; X`09 `7D X`09 while (fillsrc <= p_end && fillsrc != repl_beginning && X`09 p_char`5Bfillsrc`5D != ' ') X`09`09fillsrc++; X#ifdef DEBUGGING X`09 if (debug & 64) X`09`09printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n", X`09`09 fillsrc,filldst,repl_beginning,p_end+1); X#endif X`09 assert(fillsrc==p_end+1 `7C`7C fillsrc==repl_beginning); X`09 assert(filldst==p_end+1 `7C`7C filldst==repl_beginning); X`09`7D X `7D X else `7B`09`09`09`09/* normal diff--fake it up */ X`09char hunk_type; X`09Reg3 int i; X`09LINENUM min, max; X`09long line_beginning = ftell(pfp); X X`09p_context = 0; X`09ret = pgets(buf, sizeof buf, pfp); X`09p_input_line++; X`09if (ret == Nullch `7C`7C !isdigit(*buf)) `7B X`09 next_intuit_at(line_beginning,p_input_line); X`09 return FALSE; X`09`7D X`09p_first = (LINENUM)atol(buf); X`09for (s=buf; isdigit(*s); s++) ; X`09if (*s == ',') `7B X`09 p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; X`09 while (isdigit(*s)) s++; X`09`7D X`09else X`09 p_ptrn_lines = (*s != 'a'); X`09hunk_type = *s; X`09if (hunk_type == 'a') X`09 p_first++;`09`09`09/* do append rather than insert */ X`09min = (LINENUM)atol(++s); X`09for (; isdigit(*s); s++) ; X`09if (*s == ',') X`09 max = (LINENUM)atol(++s); X`09else X`09 max = min; X`09if (hunk_type == 'd') X`09 min++; X`09p_end = p_ptrn_lines + 1 + max - min + 1; X`09if (p_end > MAXHUNKSIZE) X`09 fatal4("Hunk too large (%ld lines) at line %ld: %s", X`09`09 p_end, p_input_line, buf); X`09while (p_end >= hunkmax) X`09 grow_hunkmax(); X`09p_newfirst = min; X`09p_repl_lines = max - min + 1; X`09Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1); X`09p_line`5B0`5D = savestr(buf); X`09if (out_of_mem) `7B X`09 p_end = -1; X`09 return FALSE; X`09`7D X`09p_char`5B0`5D = '*'; X`09for (i=1; i<=p_ptrn_lines; i++) `7B X`09 ret = pgets(buf, sizeof buf, pfp); X`09 p_input_line++; X`09 if (ret == Nullch) X`09`09fatal2("Unexpected end of file in patch at line %ld.\n", X`09`09 p_input_line); X`09 if (*buf != '<') X`09`09fatal2("< expected at line %ld of patch.\n", p_input_line); X`09 p_line`5Bi`5D = savestr(buf+2); X`09 if (out_of_mem) `7B X`09`09p_end = i-1; X`09`09return FALSE; X`09 `7D X`09 p_len`5Bi`5D = strlen(p_line`5Bi`5D); X`09 p_char`5Bi`5D = '-'; X`09`7D X`09if (hunk_type == 'c') `7B X`09 ret = pgets(buf, sizeof buf, pfp); X`09 p_input_line++; X`09 if (ret == Nullch) X`09`09fatal2("Unexpected end of file in patch at line %ld.\n", X`09`09 p_input_line); X`09 if (*buf != '-') X`09`09fatal2("--- expected at line %ld of patch.\n", p_input_line); X`09`7D X`09Sprintf(buf, "--- %ld,%ld\n", min, max); X`09p_line`5Bi`5D = savestr(buf); X`09if (out_of_mem) `7B X`09 p_end = i-1; X`09 return FALSE; X`09`7D X`09p_char`5Bi`5D = '='; X`09for (i++; i<=p_end; i++) `7B X`09 ret = pgets(buf, sizeof buf, pfp); X`09 p_input_line++; X`09 if (ret == Nullch) X`09`09fatal2("Unexpected end of file in patch at line %ld.\n", X`09`09 p_input_line); X`09 if (*buf != '>') X`09`09fatal2("> expected at line %ld of patch.\n", p_input_line); X`09 p_line`5Bi`5D = savestr(buf+2); X`09 if (out_of_mem) `7B X`09`09p_end = i-1; X`09`09return FALSE; X`09 `7D X`09 p_len`5Bi`5D = strlen(p_line`5Bi`5D); +-+-+-+-+-+-+-+- END OF PART 11 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 12 -+-+-+-+-+-+-+-+ X`09 p_char`5Bi`5D = '+'; X`09`7D X `7D X if (reverse)`09`09`09/* backwards patch? */ X`09if (!pch_swap()) X`09 say1("Not enough memory to swap next hunk!\n"); X#ifdef DEBUGGING X if (debug & 2) `7B X`09int i; X`09char special; X X`09for (i=0; i <= p_end; i++) `7B X`09 if (i == p_ptrn_lines) X`09`09special = '`5E'; X`09 else X`09`09special = ' '; X`09 fprintf(stderr, "%3d %c %c %s", i, p_char`5Bi`5D, special, p_line`5Bi V`5D); X`09 Fflush(stderr); X`09`7D X `7D X#endif X if (p_end+1 < hunkmax)`09/* paranoia reigns supreme... */ X`09p_char`5Bp_end+1`5D = '`5E'; /* add a stopper for apply_hunk */ X return TRUE; X Xmalformed: X fatal3("Malformed patch at line %ld: %s", p_input_line, buf); X`09`09/* about as informative as "Syntax error" in C */ X return FALSE;`09/* for lint */ X`7D X X/* Input a line from the patch file, worrying about indentation. */ X Xchar * Xpgets(bf,sz,fp) Xchar *bf; Xint sz; XFILE *fp; X`7B X char *ret = fgets(bf, sz, fp); X Reg1 char *s; X Reg2 int indent = 0; X X if (p_indent && ret != Nullch) `7B X`09for (s=buf; indent < p_indent && (*s == ' ' `7C`7C *s == '\t'); s++) `7B X`09 if (*s == '\t') X`09`09indent += 8 - (indent % 7); X`09 else X`09`09indent++; X`09`7D X`09if (buf != s) X`09 Strcpy(buf, s); X `7D X return ret; X`7D X X/* Reverse the old and new portions of the current hunk. */ X Xbool Xpch_swap() X`7B X char **tp_line;`09`09/* the text of the hunk */ X short *tp_len;`09`09/* length of each line */ X char *tp_char;`09`09/* +, -, and ! */ X Reg1 LINENUM i; X Reg2 LINENUM n; X bool blankline = FALSE; X Reg3 char *s; X X i = p_first; X p_first = p_newfirst; X p_newfirst = i; X `20 X /* make a scratch copy */ X X tp_line = p_line; X tp_len = p_len; X tp_char = p_char; X p_line = Null(char**);`09/* force set_hunkmax to allocate again */ X p_len = Null(short*); X p_char = Nullch; X set_hunkmax(); X if (p_line == Null(char**) `7C`7C p_len == Null(short*) `7C`7C p_char == V Nullch) `7B X#ifndef lint X`09if (p_line == Null(char**)) X`09 free((char*)p_line); X`09p_line = tp_line; X`09if (p_len == Null(short*)) X`09 free((char*)p_len); X`09p_len = tp_len; X#endif X`09if (p_char == Nullch) X`09 free((char*)p_char); X`09p_char = tp_char; X`09return FALSE;`09`09/* not enough memory to swap hunk! */ X `7D X X /* now turn the new into the old */ X X i = p_ptrn_lines + 1; X if (tp_char`5Bi`5D == '\n') `7B`09`09/* account for possible blank line V */ X`09blankline = TRUE; X`09i++; X `7D X if (p_efake >= 0) `7B`09`09`09/* fix non-freeable ptr range */ X`09n = p_end - i + 1; X`09if (p_efake > i) X`09 n = -n; X`09p_efake += n; X`09p_bfake += n; X `7D X for (n=0; i <= p_end; i++,n++) `7B X`09p_line`5Bn`5D = tp_line`5Bi`5D; X`09p_char`5Bn`5D = tp_char`5Bi`5D; X`09if (p_char`5Bn`5D == '+') X`09 p_char`5Bn`5D = '-'; X`09p_len`5Bn`5D = tp_len`5Bi`5D; X `7D X if (blankline) `7B X`09i = p_ptrn_lines + 1; X`09p_line`5Bn`5D = tp_line`5Bi`5D; X`09p_char`5Bn`5D = tp_char`5Bi`5D; X`09p_len`5Bn`5D = tp_len`5Bi`5D; X`09n++; X `7D X assert(p_char`5B0`5D == '='); X p_char`5B0`5D = '*'; X for (s=p_line`5B0`5D; *s; s++) X`09if (*s == '-') X`09 *s = '*'; X X /* now turn the old into the new */ X X assert(tp_char`5B0`5D == '*'); X tp_char`5B0`5D = '='; X for (s=tp_line`5B0`5D; *s; s++) X`09if (*s == '*') X`09 *s = '-'; X for (i=0; n <= p_end; i++,n++) `7B X`09p_line`5Bn`5D = tp_line`5Bi`5D; X`09p_char`5Bn`5D = tp_char`5Bi`5D; X`09if (p_char`5Bn`5D == '-') X`09 p_char`5Bn`5D = '+'; X`09p_len`5Bn`5D = tp_len`5Bi`5D; X `7D X assert(i == p_ptrn_lines + 1); X i = p_ptrn_lines; X p_ptrn_lines = p_repl_lines; X p_repl_lines = i; X#ifndef lint X if (tp_line == Null(char**)) X`09free((char*)tp_line); X if (tp_len == Null(short*)) X`09free((char*)tp_len); X#endif X if (tp_char == Nullch) X`09free((char*)tp_char); X return TRUE; X`7D X X/* Return the specified line position in the old file of the old context. */ X XLINENUM Xpch_first() X`7B X return p_first; X`7D X X/* Return the number of lines of old context. */ X XLINENUM Xpch_ptrn_lines() X`7B X return p_ptrn_lines; X`7D X X/* Return the probable line position in the new file of the first line. */ X XLINENUM Xpch_newfirst() X`7B X return p_newfirst; X`7D X X/* Return the number of lines in the replacement text including context. */ X XLINENUM Xpch_repl_lines() X`7B X return p_repl_lines; X`7D X X/* Return the number of lines in the whole hunk. */ X XLINENUM Xpch_end() X`7B X return p_end; X`7D X X/* Return the number of context lines before the first changed line. */ X XLINENUM Xpch_context() X`7B X return p_context; X`7D X X/* Return the length of a particular patch line. */ X Xshort Xpch_line_len(line) XLINENUM line; X`7B X return p_len`5Bline`5D; X`7D X X/* Return the control character (+, -, *, !, etc) for a patch line. */ X Xchar Xpch_char(line) XLINENUM line; X`7B X return p_char`5Bline`5D; X`7D X X/* Return a pointer to a particular patch line. */ X Xchar * Xpfetch(line) XLINENUM line; X`7B X return p_line`5Bline`5D; X`7D X X/* Return where in the patch file this hunk began, for error messages. */ X XLINENUM Xpch_hunk_beg() X`7B X return p_hunk_beg; X`7D X X/* Apply an ed script by feeding ed itself. */ X Xvoid Xdo_ed_script() X`7B X#ifdef VMS X printf ("Sorry, there's no ed on VMS.\n"); X exit(0); X#else X Reg1 char *t; X Reg2 long beginning_of_this_line; X Reg3 bool this_line_is_command = FALSE; X Reg4 FILE *pipefp; X FILE *popen(); X X if (!skip_rest_of_patch) `7B X`09while (unlink(TMPOUTNAME) >= 0); X`09copy_file(filearg`5B0`5D, TMPOUTNAME); X`09if (verbose) X`09 Sprintf(buf, "/bin/ed %s", TMPOUTNAME); X`09else X`09 Sprintf(buf, "/bin/ed - %s", TMPOUTNAME); X`09pipefp = popen(buf, "w"); X `7D X for (;;) `7B X`09beginning_of_this_line = ftell(pfp); X`09if (pgets(buf, sizeof buf, pfp) == Nullch) `7B X`09 next_intuit_at(beginning_of_this_line,p_input_line); X`09 break; X`09`7D X`09p_input_line++; X`09for (t=buf; isdigit(*t) `7C`7C *t == ','; t++) ; X`09this_line_is_command = (isdigit(*buf) && X`09 (*t == 'd' `7C`7C *t == 'c' `7C`7C *t == 'a') ); X`09if (this_line_is_command) `7B X`09 if (!skip_rest_of_patch) X`09`09fputs(buf, pipefp); X`09 if (*t != 'd') `7B X`09`09while (pgets(buf, sizeof buf, pfp) != Nullch) `7B X`09`09 p_input_line++; X`09`09 if (!skip_rest_of_patch) X`09`09`09fputs(buf, pipefp); X`09`09 if (strEQ(buf, ".\n")) X`09`09`09break; X`09`09`7D X`09 `7D X`09`7D X`09else `7B X`09 next_intuit_at(beginning_of_this_line,p_input_line); X`09 break; X`09`7D X `7D X if (skip_rest_of_patch) X`09return; X fprintf(pipefp, "w\n"); X fprintf(pipefp, "q\n"); X Fflush(pipefp); X Pclose(pipefp); X ignore_signals(); X if (move_file(TMPOUTNAME, outname) < 0) `7B X`09toutkeep = TRUE; X`09chmod(TMPOUTNAME, filemode); X `7D X else X`09chmod(outname, filemode); X set_signals(); X#endif /* VMS */ X`7D $ CALL UNPACK [.SRC]PCH.C;1 830158556 $ create 'f' X/* $Header: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $ X * X * $Log:`09pch.h,v $ X * Revision 2.0.1.1 87/01/30 22:47:16 lwall X * Added do_ed_script(). X *`20 X * Revision 2.0 86/09/17 15:39:57 lwall X * Baseline for netwide release. X *`20 X */ X XEXT FILE *pfp INIT(Nullfp);`09`09/* patch file pointer */ X Xvoid re_patch(); Xvoid open_patch_file(); Xvoid set_hunkmax(); Xvoid grow_hunkmax(); Xbool there_is_another_patch(); Xint intuit_diff_type(); Xvoid next_intuit_at(); Xvoid skip_to(); Xbool another_hunk(); Xbool pch_swap(); Xchar *pfetch(); Xshort pch_line_len(); XLINENUM pch_first(); XLINENUM pch_ptrn_lines(); XLINENUM pch_newfirst(); XLINENUM pch_repl_lines(); XLINENUM pch_end(); XLINENUM pch_context(); XLINENUM pch_hunk_beg(); Xchar pch_char(); Xchar *pfetch(); Xchar *pgets(); Xvoid do_ed_script(); $ CALL UNPACK [.SRC]PCH.H;1 1832979341 $ create 'f' X#include "EXTERN.h" X#include "common.h" X#include "INTERN.h" X#include "util.h" X X/* Rename a file, copying it if necessary. */ X Xint Xmove_file(from,to) Xchar *from, *to; X`7B X char bakname`5B512`5D; X Reg1 char *s; X Reg2 int i; X Reg3 int fromfd; X X /* to stdout? */ X X if (strEQ(to, "-")) `7B X#ifdef DEBUGGING X`09if (debug & 4) X`09 say2("Moving %s to stdout.\n", from); X#endif X#ifdef VMS X`09fromfd = open(from, 0, "mbc=64", "mbf=2"); X#else X `09fromfd = open(from, 0); X#endif X`09if (fromfd < 0) X`09 fatal2("patch: internal error, can't reopen %s\n", from); X`09while ((i=read(fromfd, buf, sizeof buf)) > 0) X`09 if (write(1, buf, i) != 1) X`09`09fatal1("patch: write failed\n"); X`09Close(fromfd); X`09return 0; X `7D X X#ifdef VMS X /* This is not robust -- we just rename the file, hoping for the best. * V/ X /* This is not efficient, but for simplicity sake, we simply copy`09*/ X /* the file, and remove the source.`09`09`09`09`09*/ X copy_file(from, to); X delete(from); X return 0; X#else X Strcpy(bakname, to); X Strcat(bakname, origext?origext:ORIGEXT); X if (stat(to, &filestat) >= 0) `7B`09/* output file exists */ X`09dev_t to_device = filestat.st_dev; X`09ino_t to_inode = filestat.st_ino; X`09char *simplename = bakname; X`09 X`09for (s=bakname; *s; s++) `7B X`09 if (*s == '/') X`09`09simplename = s+1; X`09`7D X`09/* find a backup name that is not the same file */ X`09while (stat(bakname, &filestat) >= 0 && X`09`09to_device == filestat.st_dev && to_inode == filestat.st_ino) `7B X`09 for (s=simplename; *s && !islower(*s); s++) ; X`09 if (*s) X`09`09*s = toupper(*s); X`09 else X`09`09Strcpy(simplename, simplename+1); X`09`7D X`09while (unlink(bakname) >= 0) ;`09/* while() is for benefit of Eunice */ X#ifdef DEBUGGING X`09if (debug & 4) X`09 say3("Moving %s to %s.\n", to, bakname); X#endif X`09if (link(to, bakname) < 0) `7B X`09 say3("patch: can't backup %s, output is in %s\n", X`09`09to, from); X`09 return -1; X`09`7D X`09while (unlink(to) >= 0) ; X `7D X#ifdef DEBUGGING X if (debug & 4) X`09say3("Moving %s to %s.\n", from, to); X#endif X if (link(from, to) < 0) `7B`09`09/* different file system? */ X`09Reg4 int tofd; X`09 X`09tofd = creat(to, 0666); X`09if (tofd < 0) `7B X`09 say3("patch: can't create %s, output is in %s.\n", X`09 to, from); X`09 return -1; X`09`7D X`09fromfd = open(from, 0); X`09if (fromfd < 0) X`09 fatal2("patch: internal error, can't reopen %s\n", from); X`09while ((i=read(fromfd, buf, sizeof buf)) > 0) X`09 if (write(tofd, buf, i) != i) X`09`09fatal1("patch: write failed\n"); X`09Close(fromfd); X`09Close(tofd); X `7D X Unlink(from); X#endif /* VMS */ X return 0; X`7D X X/* Copy a file. */ X Xvoid Xcopy_file(from,to) Xchar *from, *to; X`7B X Reg3 int tofd; X Reg2 int fromfd; X Reg1 int i; X `20 X tofd = creat(to, 0666 X#ifdef VMS X`09`09`09, "mbc=64", "mbf=2" X#endif X`09`09`09`09); X if (tofd < 0) X`09fatal2("patch: can't create %s.\n", to); X fromfd = open(from, 0 X#ifdef VMS X`09`09`09, "mbc=64", "mbf=2" X#endif X`09`09`09`09); X if (fromfd < 0) X`09fatal2("patch: internal error, can't reopen %s\n", from); X while ((i=read(fromfd, buf, sizeof buf)) > 0) X`09if (write(tofd, buf, i) != i) X`09 fatal2("patch: write (%s) failed\n", to); X Close(fromfd); X Close(tofd); X`7D X X/* Allocate a unique area for a string. */ X Xchar * Xsavestr(s) XReg1 char *s; X`7B X Reg3 char *rv; X Reg2 char *t; X X if (!s) X`09s = "Oops"; X t = s; X while (*t++); X rv = malloc((MEM) (t - s)); X if (rv == Nullch) `7B X`09if (using_plan_a) X`09 out_of_mem = TRUE; X`09else X`09 fatal1("patch: out of memory (savestr)\n"); X `7D X else `7B X`09t = rv; X`09while (*t++ = *s++); X `7D X return rv; X`7D X X#if defined(lint) && defined(CANVARARG) X X/*VARARGS ARGSUSED*/ Xsay(pat) char *pat; `7B ; `7D X/*VARARGS ARGSUSED*/ Xfatal(pat) char *pat; `7B ; `7D X/*VARARGS ARGSUSED*/ Xask(pat) char *pat; `7B ; `7D X X#else X X/* Vanilla terminal output (buffered). */ X Xvoid Xsay(pat,arg1,arg2,arg3) Xchar *pat; Xint arg1,arg2,arg3; X`7B X fprintf(stderr, pat, arg1, arg2, arg3); X Fflush(stderr); X`7D X X/* Terminal output, pun intended. */ X Xvoid`09`09`09`09/* very void */ Xfatal(pat,arg1,arg2,arg3) Xchar *pat; Xint arg1,arg2,arg3; X`7B X void my_exit(); X X say(pat, arg1, arg2, arg3); X my_exit(1); X`7D X X/* Get a response from the user, somehow or other. */ X Xvoid Xask(pat,arg1,arg2,arg3) Xchar *pat; Xint arg1,arg2,arg3; X`7B X int ttyfd; X int r; X bool tty2 = isatty(2); X X Sprintf(buf, pat, arg1, arg2, arg3); X Fflush(stderr); X write(2, buf, strlen(buf)); X if (tty2) `7B`09`09`09`09/* might be redirected to a file */ X`09r = read(2, buf, sizeof buf); X `7D X else if (isatty(1)) `7B`09`09/* this may be new file output */ X`09Fflush(stdout); X`09write(1, buf, strlen(buf)); X`09r = read(1, buf, sizeof buf); X `7D X else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) `7B X`09`09`09`09`09/* might be deleted or unwriteable */ X`09write(ttyfd, buf, strlen(buf)); X`09r = read(ttyfd, buf, sizeof buf); X`09Close(ttyfd); X `7D X else if (isatty(0)) `7B`09`09/* this is probably patch input */ X`09Fflush(stdin); X`09write(0, buf, strlen(buf)); X`09r = read(0, buf, sizeof buf); X `7D X else `7B`09`09`09`09/* no terminal at all--default it */ X`09buf`5B0`5D = '\n'; X`09r = 1; X `7D X if (r <= 0) X`09buf`5B0`5D = 0; X else X`09buf`5Br`5D = '\0'; X if (!tty2) X`09say1(buf); X`7D X#endif lint X X/* How to handle certain events when not in a critical region. */ X Xvoid Xset_signals() X`7B X void my_exit(); X X#ifndef lint X if (signal(SIGHUP, SIG_IGN) != SIG_IGN) X`09Signal(SIGHUP, my_exit); X if (signal(SIGINT, SIG_IGN) != SIG_IGN) +-+-+-+-+-+-+-+- END OF PART 12 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 13 -+-+-+-+-+-+-+-+ X`09Signal(SIGINT, my_exit); X#endif X`7D X X/* How to handle certain events when in a critical region. */ X Xvoid Xignore_signals() X`7B X#ifndef lint X Signal(SIGHUP, SIG_IGN); X Signal(SIGINT, SIG_IGN); X#endif X`7D X X/* Make sure we'll have the directories to create a file. */ X Xvoid Xmakedirs(filename,striplast) XReg1 char *filename; Xbool striplast; X`7B X char tmpbuf`5B256`5D; X Reg2 char *s = tmpbuf; X char *dirv`5B20`5D; X Reg3 int i; X Reg4 int dirvp = 0; X X while (*filename) `7B X`09if (*filename == '/') `7B X`09 filename++; X`09 dirv`5Bdirvp++`5D = s; X`09 *s++ = '\0'; X`09`7D X`09else `7B X`09 *s++ = *filename++; X`09`7D X `7D X *s = '\0'; X dirv`5Bdirvp`5D = s; X if (striplast) X`09dirvp--; X if (dirvp < 0) X`09return; X strcpy(buf, "mkdir"); X s = buf; X for (i=0; i<=dirvp; i++) `7B X`09while (*s) s++; X`09*s++ = ' '; X`09strcpy(s, tmpbuf); X`09*dirv`5Bi`5D = '/'; X `7D X system(buf); X`7D X X/* Make filenames more reasonable. */ X Xchar * Xfetchname(at,strip_leading,assume_exists) Xchar *at; Xint strip_leading; Xint assume_exists; X`7B X char *s; X char *name; X Reg1 char *t; X char tmpbuf`5B200`5D; X X if (!at) X`09return Nullch; X s = savestr(at); X for (t=s; isspace(*t); t++) ; X name = t; X#ifdef DEBUGGING X if (debug & 128) X`09say4("fetchname %s %d %d\n",name,strip_leading,assume_exists); X#endif X if (strnEQ(name, "/dev/null", 9))`09/* so files can be created by diffin Vg */ X`09return Nullch;`09`09`09/* against /dev/null. */ X for (; *t && !isspace(*t); t++) X`09if (*t == '/') X`09 if (--strip_leading >= 0) X`09`09name = t+1; X *t = '\0'; X if (name != s && *s != '/') `7B X`09name`5B-1`5D = '\0'; X`09if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) `7B X`09 name`5B-1`5D = '/'; X`09 name=s; X`09`7D X `7D X name = savestr(name); X Sprintf(tmpbuf, "RCS/%s", name); X free(s); X if (stat(name, &filestat) < 0 && !assume_exists) `7B X#ifdef VMS X`09free(name); X`09name = Nullch; X `7D X#else X`09Strcat(tmpbuf, RCSSUFFIX); X`09if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) `7B X`09 Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name); X`09 if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) `7B X`09`09free(name); X`09`09name = Nullch; X`09 `7D X`09`7D X `7D X#endif /* VMS */ X return name; X`7D $ CALL UNPACK [.SRC]UTIL.C;1 1581668323 $ create 'f' X/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $ X * X * $Log:`09util.h,v $ X * Revision 2.0 86/09/17 15:40:06 lwall X * Baseline for netwide release. X *`20 X */ X X/* and for those machine that can't handle a variable argument list */ X X#ifdef CANVARARG X X#define say1 say X#define say2 say X#define say3 say X#define say4 say X#define ask1 ask X#define ask2 ask X#define ask3 ask X#define ask4 ask X#define fatal1 fatal X#define fatal2 fatal X#define fatal3 fatal X#define fatal4 fatal X X#else /* hope they allow multi-line macro actual arguments */ X X#ifdef lint X X#define say1(a) say(a, 0, 0, 0) X#define say2(a,b) say(a, (b)==(b), 0, 0) X#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0) X#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d)) X#define ask1(a) ask(a, 0, 0, 0) X#define ask2(a,b) ask(a, (b)==(b), 0, 0) X#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0) X#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d)) X#define fatal1(a) fatal(a, 0, 0, 0) X#define fatal2(a,b) fatal(a, (b)==(b), 0, 0) X#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0) X#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d)) X X#else /* lint */ X /* if this doesn't work, try defining CANVARARG above */ X#define say1(a) say(a, Nullch, Nullch, Nullch) X#define say2(a,b) say(a, b, Nullch, Nullch) X#define say3(a,b,c) say(a, b, c, Nullch) X#define say4 say X#define ask1(a) ask(a, Nullch, Nullch, Nullch) X#define ask2(a,b) ask(a, b, Nullch, Nullch) X#define ask3(a,b,c) ask(a, b, c, Nullch) X#define ask4 ask X#define fatal1(a) fatal(a, Nullch, Nullch, Nullch) X#define fatal2(a,b) fatal(a, b, Nullch, Nullch) X#define fatal3(a,b,c) fatal(a, b, c, Nullch) X#define fatal4 fatal X X#endif /* lint */ X X/* if neither of the above work, join all multi-line macro calls. */ X#endif X XEXT char serrbuf`5BBUFSIZ`5D;`09`09/* buffer for stderr */ X Xchar *fetchname(); Xint move_file(); Xvoid copy_file(); Xvoid say(); Xvoid fatal(); Xvoid ask(); Xchar *savestr(); Xvoid set_signals(); Xvoid ignore_signals(); Xvoid makedirs(); $ CALL UNPACK [.SRC]UTIL.H;1 1802118602 $ create 'f' X/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $ X * X * $Log:`09version.c,v $ X * Revision 2.0 86/09/17 15:40:11 lwall X * Baseline for netwide release. X *`20 X */ X X#include "EXTERN.h" X#include "common.h" X#include "util.h" X#include "INTERN.h" X#include "patchlevel.h" X#include "version.h" X X/* Print out the version number and die. */ X Xvoid Xversion() X`7B X extern char rcsid`5B`5D; X X#ifdef lint X rcsid`5B0`5D = rcsid`5B0`5D; X#else X fatal3("%s\nPatch level: %d\n", rcsid, PATCHLEVEL); X#endif X`7D $ CALL UNPACK [.SRC]VERSION.C;1 1661809282 $ create 'f' X/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $ X * X * $Log:`09version.h,v $ X * Revision 2.0 86/09/17 15:40:14 lwall X * Baseline for netwide release. X *`20 X */ X Xvoid version(); $ CALL UNPACK [.SRC]VERSION.H;1 122769530 $ v=f$verify(v) $ EXIT !