-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
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.c
X$ cc /obj=`5B-.bld`5D inp.c
X$ cc /obj=`5B-.bld`5D util.c
X$ cc /obj=`5B-.bld`5D version.c
X$ cc /obj=`5B-.bld`5D pch.c
X$ cc /obj=`5B-.bld`5D argproc.c
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;3 1648977705
$ 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 <ctype.h>
X#include <signal.h>
X#include <stdio.h>
X#include <assert.h>
X#include <sys/types.h>
X#include <sys/stat.h>
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 <alloc.h>
X#include <errno.h>
X#include <process.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
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 <stdio.h>
X#include <ctype.h>
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
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;
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 = ' ';
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
+-+-+-+-+-+-+-+-  END  OF PART 2 +-+-+-+-+-+-+-+-
