From:	MERC::"uunet!crdgw1.ge.com!root" 20-APR-1992 00:33:44.91
To:	everhart
CC:	
Subj:	Announcing DX v2.3, a VAX/VMS directory browser/editor

From:	RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP@CRDGW2
To:	Everhart@Arisia@MRGATE

Received:  by crdgw1.ge.com (5.57/GE 1.139)
	 id AA12157; Sun, 19 Apr 92 16:33:46 EDT
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Sun, 19 APR 92 11:52:03 PDT
Received: by ucbvax.Berkeley.EDU (5.63/1.43)
	id AA06445; Sun, 19 Apr 92 11:07:16 -0700
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 17 Apr 92 05:54:24 GMT
From: oracle!unrepliable!bounce@decwrl.dec.com  (Chau-Kuang Hung)
Organization: Oracle Corporation, Belmont, CA
Subject: Announcing DX v2.3, a VAX/VMS directory browser/editor
Message-Id: <CHUNG.92Apr16215424@appseq.oracle.com>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

DX (Directory eXtension) is a VAX/VMS utility that performs various
file operations on a VT100 or upper terminals.  It allows you to
delete, type, copy, set protection, compare, and edit one or many of
the files in a single directory at once.  DX is an customizable,
flexible, real-time directory browser/editor.  You can also open multiple 
windows on the the same or different directories.

DX provides the following main features:

  o Flexible display and sorting

  o Pull-down menu for point-and-shoot interface

  o Display sub-directories and directory contents with flexible "filters"

  o Multiple inclusion/exclusion patterns in file operations

  o Multiple windows provides different views

  o Display a tree-like directory structure in a scrollable window


Please direct all comments, suggestions, and bugs to

      Chau-Kuang Hung (chung@appseq.us.oracle.com)
      Oracle Corporation
      300 Oracle Parkway
      BOX 659304
      Redwood Shores, CA 94065

$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On 16-APR-1992 14:38:21.40   By user HWU 
$!
$! 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 25 PARTS, TO KEEP EACH PART
$!  BELOW 60 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. AAAREAD.ME;23
$!       2. DIFF.C;23
$!       3. DIFF.H;23
$!       4. DIRECT.C;23
$!       5. DIRECT.H;23
$!       6. DIRECTKPD.C;23
$!       7. DIRECTKPD.H;23
$!       8. DIRECTQUE.C;23
$!       9. DIRECTQUE.H;23
$!      10. DX$BUILD.COM;23
$!      11. DX$STARTUP.DAT;23
$!      12. DX.C;23
$!      13. DX.CLD;23
$!      14. DX.H;23
$!      15. ENDECODE.C;23
$!      16. ENDECODE.H;23
$!      17. FILER.C;23
$!      18. FILER.H;23
$!      19. FILERAPP.C;23
$!      20. FILERAPP.H;23
$!      21. FILERCPY.C;23
$!      22. FILERCPY.H;23
$!      23. FILERCUS.C;23
$!      24. FILERCUS.H;23
$!      25. FILERDEC.C;23
$!      26. FILERDEC.H;23
$!      27. FILERDEL.C;23
$!      28. FILERDEL.H;23
$!      29. FILERDIF.C;23
$!      30. FILERDIF.H;23
$!      31. FILEREDT.C;23
$!      32. FILEREDT.H;23
$!      33. FILERENC.C;23
$!      34. FILERENC.H;23
$!      35. FILEREXE.C;23
$!      36. FILEREXE.H;23
$!      37. FILERFLT.C;23
$!      38. FILERFLT.H;23
$!      39. FILERFND.C;23
$!      40. FILERFND.H;23
$!      41. FILERKPD.C;23
$!      42. FILERKPD.H;23
$!      43. FILERLAU.C;23
$!      44. FILERLAU.H;23
$!      45. FILEROPT.C;23
$!      46. FILEROPT.H;23
$!      47. FILERPRO.C;23
$!      48. FILERPRO.H;23
$!      49. FILERPRT.C;23
$!      50. FILERPRT.H;23
$!      51. FILERPUR.C;23
$!      52. FILERPUR.H;23
$!      53. FILERQUE.C;23
$!      54. FILERQUE.H;23
$!      55. FILERREN.C;23
$!      56. FILERREN.H;23
$!      57. FILERSRT.C;23
$!      58. FILERSRT.H;23
$!      59. FILERSTA.C;23
$!      60. FILERSTA.H;23
$!      61. FILERTYP.C;23
$!      62. FILERTYP.H;23
$!      63. FILERWIN.C;23
$!      64. FILERWIN.H;23
$!      65. FINDFILE.C;23
$!      66. FINDFILE.H;23
$!      67. GLOBAL.H;23
$!      68. INQUIRE.C;23
$!      69. INQUIRE.H;23
$!      70. MENUNAVI.C;23
$!      71. MENUNAVI.H;23
$!
$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'
XPRODUCT NAME
XDX (Directory eXtension), Version 2.3
X
X
XGENERAL DESCRIPTION
XDX is a VAX/VMS utility that performs many file operations on a VT100`20
Xor upper type terminal.  It can be used to delete, edit, or rename
Xfiles in the current directory.  DX can also create a hardcopy listing`20
Xof all the files displayed.
X
X
XFEATURES
X
Xo Flexible display and sorting
X
Xo Pull-down menu for point-and-shoot interface
X
Xo Display sub-directories and directory contents with flexible "filters"
X
Xo Multiple inclusion/exclusion patterns in file operations
X
Xo Multiple windows provides different views
X
Xo Display a tree-like directory structure in a scrollable window
X
X
XSOURCE FILES
XThis directory holds the latest distribution version of DX.  It includes
Xthe following files:
X
X`09AAAREAD.ME`09DX_BUILD.COM`09DX.COM`09`09DX.CLD
X`09DX.HLP`09`09DIRECT.C`09DIRECT.H`09DIRECTKPD.C
X`09DIRECTKPD.H`09DIRECTQUE.C`09DIRECTQUE.H`09DIFF.C
X`09DIFF.H`09`09DX.C`09`09DX.H`09`09ENDECODE.C
X`09ENDECODE.H`09FILER.C`09`09FILER.H`09`09FILERAPP.C
X`09FILERAPP.H`09FILERCPY.C`09FILERCPY.H`09FILERCUS.C
X`09FILERCUS.H`09FILERDEC.C`09FILERDEC.H`09FILERDEL.C
X`09FILERDEL.H`09FILERDIF.C`09FILERDIF.H`09FILEREDT.C
X`09FILEREDT.H`09FILERENC.C`09FILERENC.H`09FILEREXE.C
X`09FILEREXE.H`09FILERFLT.C`09FILERFLT.H`09FILREFND.C
X`09FILREFND.H`09FILERKPD.C`09FILERKPD.H`09FILERLAU.C
X`09FILERLAU.H`09FILERPRO.C`09FILERPRO.H`09FILERPRT.C
X`09FILERPRT.H`09FILERPUR.C`09FILERPUR.H`09FILEROPT.C
X`09FILEROPT.H`09FILERQUE.C`09FILERQUE.H`09FILERREN.C
X`09FILERREN.H`09FILERSTA.C`09FILERSTA.H`09FILERSRT.C
X`09FILERSRT.H`09FILERTYP.C`09FILERTYP.H`09FILERWIN.C
X`09FILERWIN.H`09FINDFILE.C`09FINDFILE.H`09INQUIRE.C
X`09INQUIRE.H`09MENUNAVI.C`09MENUNAVI.H`09GLOBAL.H
X`09DX$STARTUP.DAT
X
XThe file `60dx_build.com' helps automate the process of building and`20
Xinstalling DX. `20
X
XThe file `60dx.com' in this directory defines logical names and commands`20
Xsuch as `60DX', so you must edit it to specify the file and directory names`
V20
Xused.  This file must be executed in each session to enable you to run
Xthe installed DX.  Also, `60dx.com' use the file `60dx.cld' which contains t
Vhe`20
Xcommand definitions (i.e. command parameters and qualifiers) for DX.
X
XThe file `60dx$startup.dat' is an init file that is loaded from your home
Xdirectory when DX starts.  It is a text file that can be viewed or changed
Xusing any editor.   `20
X
XPlease direct all comments, suggestions, and bugs to
X
X      Chau-Kuang Hung (chung@us.oracle.com)
X      Oracle Corporation
X      300 Oracle Parkway
X      BOX 659304
X      Redwood Shores, CA 94065
X
$ CALL UNPACK AAAREAD.ME;23 2914859
$ create 'f'
X/*
X**++
X**  FACILITY:  DIFF.C
X**
X**  MODULE DESCRIPTION:
X**
X**      This module compares two arrays of lines (representing
X**`09files) and reports the sequences of consecutive matching
X**`09lines between them using the "recursive longest matching
X**`09sequence" algorithm. `20
X**
X**  AUTHORS:
X**`09Steppe, Tom. "File Comparison Algorithms." Dr. Dobb's`20
X**`09Journal, #131 (Sep 1987): 54-60.
X**
X**  CREATION DATE:  2-21-1991
X**
X**
X**  MODIFICATION HISTORY:
X**
X**      `7B@tbs@`7D...
X**--
X*/
X
X
X/*
X**
X**  INCLUDE FILES
X**
X*/
X#ifdef vax11c
X#include stdio
X#include ctype
X#include string
X#include stdlib
X#include rms
X#include descrip
X#include "diff.h"
X#else
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include <malloc.h>
X#include "diff.h"
X#endif
X
X
X/*
X**
X**  MACRO DEFINITIONS
X**
X*/
X
X#define TRUE`091
X#define FALSE`090
X
X/**  Maximum and Minimum macro  **/
X#define max(x, y)`09(((x) > (y)) ? (x) : (y))
X#define min(x, y)`09(((x) < (y)) ? (x) : (y))
X
X/** Value to indicate identical strings with strcmp  **/
X#define ALIKE`090
X
X/**  Mask for number of bits in hash code (12 bits)  **/
X#define MASK`09(unsigned int) 0x0FFFF
X
X/** Number of possible hash codes  **/
X#define HASHSIZ`09(MASK+1)
X
X/*
X**
X**  GLOBAL DECLARATIONS
X**
X**/
X
Xint diff_sec,   `09`09    /**  Number of diff sections  **/
X    diff_line;    `09`09    /**  Number of diff lines  **/
X
Xint diff_beg1,    `09`09    /**  First line# for diff sec in file 1  **/
X    diff_beg2;    `09`09    /**  First line# for diff sec in file 2  **/
X
X/*
X**
X**  INTERNAL FUNCTION PROTOTYPE DECLARATIONS
X**
X**/
X
Xstatic BOOLEAN get_inf (char *, TXTINF *, int, FILEINF *);
Xstatic HASH calc_hash (TXTINF);
Xstatic void fnd_seq (FILEINF *, int, int, FILEINF *, int, int, int);
Xstatic BOOLEAN chk_hashes (LINEINF *, LINEINF *, int);
Xstatic int cnt_matches (TXTINF *, TXTINF *, int);
Xstatic void rpt_seq (FILEINF *, int, FILEINF *, int, int);
Xstatic void rpt_seq_1 (FILEINF *, int, int, FILEINF *, int, int);
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      compare() compares two arrays of lines and reports the
X**`09sequences of consecutive matching lines.  The zeroth
X**`09element of each array is unused so that the index into
X**`09the array is identical to the associated line number.
X**
X**  RETURN VALUE:
X**
X**      TRUE if comparison succeeded.
X**`09FALSE if not enough memory.
X**
X**--
X*/
XBOOLEAN compare (r1, a1, n1, r2, a2, n2, lngval)
Xchar *r1;`09/**  File name for #1  **/
XTXTINF *a1;`09/**  Array of lines of text in #1  **/
Xint n1;`09`09/**  Number of lines in a1 (does not count 0th element)  **/
Xchar *r2;`09/**  File name for #2  **/
XTXTINF *a2;`09/**  Array of lines of text in #2  **/
Xint n2;`09`09/**  Number of lines in a2 (does not count 0th element)  **/
Xint lngval;`09/**  "Long enough" value  **/
X`7B
X    FILEINF f1,`09`09/**  File info for #1  **/
X`09    f2;`09`09/**  File info for #2  **/
X    BOOLEAN rtn;`09/**  Return value  **/
X
X    /**  Initialize  **/
X    diff_sec = diff_line = 0;
X    diff_beg1 = diff_beg2 = 0;
X
X    /**  Gather info for each file, then compare  **/
X    if (rtn = (get_inf (r1, a1, n1, &f1) && get_inf (r2, a2, n2, &f2)))
X    `7B
X        fnd_seq (&f1, 1, n1, &f2, 1, n2, lngval);
X    `7D
X
X    /**  Output remaining difference lines  **/
X    if (!(diff_beg1 == n1 && diff_beg2 == n2))
X    `7B
X    `09rpt_seq_1 (&f1, n1, n1-diff_beg1, &f2, n2, n2-diff_beg2);
X`09diff_line++;
X    `7D
X   `20
X    /**  Output summary report  **/
X    fprintf (stdout, "\nNumber of difference sections found: %d\n", diff_sec
V);
X    fprintf (stdout, "Number of difference records found: %d\n", diff_line);
X
X    /**  Return dynamic memory to pool  **/
X    free (f1.line);`09free (f1.hashtbl);
X    free (f2.line);`09free (f2.hashtbl);
X
X    return rtn;
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      get_inf() calculates hash codes and builds a hash table
X**
X**
X**  RETURN VALUE:
X**
X**      TRUE if get_inf() succeeded.
X**`09FALSE if not enough memory.
X**
X**--
X*/
Xstatic BOOLEAN get_inf (r, a, n, f)
Xchar *r;`09    /**  File name  **/
XTXTINF *a;`09    /**  Array of lines of text  **/
Xint  n;`09`09    /**  Number of lines in a  **/
XFILEINF *f;`09    /**  File info  **/
X`7B
X    unsigned int size;`09`09/**  Size of hash table  **/
X    register int i;`09`09/**  Counter  **/
X    TBLENTRY *entry;`09`09/**  Entry in hash table  **/
X
X    f->filename = r;`09/**  Assign the file name  **/
X    f->txt = a;`09`09/**  Assign the array of text  **/
X   `20
X    /**  Allocate and initialize a hash table  **/
X    size = HASHSIZ * sizeof (TBLENTRY);
X    if (f->hashtbl = (TBLENTRY *) malloc (size))
X    `7B
X        memset ((char *) f->hashtbl, '\0', size);
X    `7D
X    else
X    `7B
X        return (FALSE);
X    `7D
X    if (n <= 0)
X    `7B`09/**  There is no lines  **/
X        f->line = NULL;
X    `7D
X    else
X    `7B
X        /**  Allocate an array of line structs  **/
X        if ((f->line =`20
X`09`09(LINEINF *) malloc ((n+1) * sizeof (LINEINF))) == NULL)
X        `7B
X            return (FALSE);
X        `7D
X        for (i = 1;  i <= n;  i++)
X        `7B   /**  Loop through the lines  **/
X            f->line`5Bi`5D.hash = calc_hash (f->txt`5Bi`5D);`09/**  Calculat
Ve hash  **/
X`09    entry = f->hashtbl + f->line`5Bi`5D.hash;`09/**  Locate entry  **/
X
X`09    /**  Update the linked list of lines iwth the same hash code  **/
X`09    f->line`5Bentry->last`5D.nxtln = i;
X`09    f->line`5Bi`5D.nxtln = 0;
X
X`09    /** Update the first and last line info in the hash table  **/
X            if (entry->frst == 0)
X            `7B
X                entry->frst = i;
X            `7D
X            entry->last = i;
X        `7D
X    `7D
X    return (TRUE);
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      calc_hash() calculates a hash code for a line of text.
X**
X**  RETURN VALUE:
X**
X**      a hash code value.
X**
X**--
X*/
Xstatic HASH calc_hash (buf)
XTXTINF buf;`09/** Line of text  **/
X`7B
X    register unsigned int chksum;   /**  Checksum  **/
X    register int`09  i;`09    /**  Counter  **/
X    char`09`09  *s;`09    /**  Pointer  **/
X    HASH`09`09  hash;`09    /**  Hash code value  **/
X
X    /**  Build up a checksum of the characters in the text   **/
X    for (chksum = 0, s = buf.content, i = 0;  i < buf.len;  chksum `5E= *s++
V, i++)
X    `7B
X        ;
X    `7D
X
X    /**  Combine the 7-bit checksum and as much of the length as is possible
V **/
X    hash = ((chksum & 0x7F) `7C ((s - buf.content) << 7)) & MASK;
X   `20
X    return (hash);
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      fnd_seq() finds a "good sequence" of lines within the given
X**`09starting and ending line numbers.  fnd_seq() then recursively
X**`09finds "good sequences" in the sections of lines above the
X**`09"good sequence" and below it.
X**
X**  RETURN VALUE:
X**
X**      none
X**
X**--
X*/
Xstatic void fnd_seq (f1, beg1, end1, f2, beg2, end2, lngval)
XFILEINF`09    *f1;`09/**  File info for #1  **/
Xint`09    beg1;`09/**  First line # to compare in #1  **/
Xint`09    end1;`09/**  Last line # to compare in #1  **/
XFILEINF     *f2;        /**  File info for #2  **/
Xint         beg2;       /**  First line # to compare in #2  **/
Xint         end2;       /**  Last line # to compare in #2  **/
Xint`09    lngval;`09/**  "Long enough" value  **/
X`7B
X    LINEINF *line1,`09/**  Line info ptr in #1  **/
X`09    *line2;`09/**  Line info ptr in #2  **/
X    register int limit;`09/**  Looping limit  **/
X    int`09    ln1,`09/**  Line number in #1  **/
X`09    ln2;`09/**  Line number in #2  **/
X    register int ln;`09/**  Working line number  **/
X    BOOLEAN go;`09`09/**  Continue to loop?  **/
X    int most,`09`09/**  Longest possible seq  **/
X`09most1,`09`09/**  Longest possible due to #1  **/
X`09most2;`09`09/**  Longest possible due to #2  **/
X    int cnt,`09`09/**  Length of longest seq  **/
X`09oldcnt,`09`09/**  Length of prev longest seq  **/
X`09n,`09`09/**  Length of cur longest seq  **/
X`09m1,`09`09/**  Line of longest seq in #1  **/
X        m2;             /**  Line of longest seq in #2  **/
X
X    /**  Initialize  **/
X    go = TRUE;
X    line1 = f1->line;
X    line2 = f2->line;
X   `20
X    /**  Initialize longest sequence info  **/
X    cnt = 0;`09`09/**  Length of longest seq  **/
X    m1 = beg1 - 1;`09/**  Line # of longest seq in #1  **/
X    m2 = beg2 - 1;      /**  Line # of longest seq in #2  **/
X    oldcnt = 0;`09`09/**  Length of prev longest seq  **/
X   `20
X    /*
X    **  Calculate max possible number of consecutive lines that
X    **`09can match (based on line # range)
X    **/
X    most1 = end1 - beg1 + 1;
X    most2 = end2 - beg2 + 1;
X   `20
X    /*
X    **`09Scan lines looking for a "good sequence".
X    **`09Compare lines in the following order of line numbers:
X    **
X    **`09`09`09    (1, 1)
X    **`09`09    (1, 2), (2, 1), (2, 2)
X    **`09    (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)
X    **`09`09`09      ...
X    **/
X    for (ln1 = beg1, ln2 = beg2;  TRUE;  ln1++, ln2++)
X    `7B
X        if (ln2 <= end2 - cnt)
X`09    /*
X`09    **`09There are enough lines left in #2 such that it
X`09    **`09is possible to find a longer sequence.
X`09    **/
X`09`7B
X            /*
X`09    **  Determine the limit in #1 that both
X`09    **`09enforces the order scheme and still makes
X`09    **`09it possible to find a longer sequence.
X`09    **/
X`09    limit = min (ln1 - 1, end1 - cnt);
X`09   `20
X`09    /**  Calculate first potential match in #1  **/
X            for (ln = f1->hashtbl`5Bline2`5Bln2`5D.hash`5D.frst; `20
X`09`09    ln && ln < beg1;  ln = line1`5Bln`5D.nxtln)
X            `7B
X                ;
X            `7D
X`09   `20
X`09    /**  Loop through the lines in #1  **/
X            for (;  ln && ln <= limit;  ln = line1`5Bln`5D.nxtln)
X            `7B
X                if (line1`5Bln`5D.hash == line2`5Bln2`5D.hash &&
X`09`09    line1`5Bln+cnt`5D.hash == line2`5Bln2+cnt`5D.hash &&
X`09`09    !(ln-m1 == ln2-m2 && ln < m1+cnt && m1 != beg1-1))
X                `7B   /*
X`09`09    **  A candidate for a longer sequence has been found`20
X`09`09    **  The current lines match, the currents + cnt match,
X`09`09    **`09and this sequence is not a subset of the longest
X`09`09    **  sequence so far.
X`09`09    **/
X
X                    /**  Calculate most possible matches  **/
X                    most = min (end1-ln+1, most2);`20
X`09`09   `20
X`09`09    /*
X`09`09    **`09First compare hash codes.  If the number of matches
X`09`09    **`09exceeds the longest sequence so far, then compare
X`09`09    **`09the actual text.
X`09`09    **/
X                    if (chk_hashes(line1+ln, line2+ln2, cnt) &&
X`09`09`09(n = cnt_matches (f1->txt+ln, f2->txt+ln2, most)) > cnt)
X                    `7B`09/**  This is the longest seq. so far  **/
X                        /**  Update longest seq info  **/
X`09`09`09oldcnt = cnt;
X`09`09`09cnt = n;
X`09`09`09m1 = ln;
X`09`09`09m2 = ln2;
X
X`09`09`09/**  If it's long enough, end the search  **/
X                        if (cnt >= lngval)
X                        `7B
X                            break;
X                        `7D
X`09`09`09
X`09`09`09/** Update limit, using new count  **/
X`09`09`09limit = min (ln1 - 1, end1 - cnt);
X                    `7D
X                `7D
X            `7D
X`09    /**  If it's long enough, end the search  **/
X            if (cnt >= lngval)
X            `7B
X                break;
X            `7D
X`09    most2--;
X        `7D
X        else
X        `7B
X            go = FALSE;`09    /**  EOF of this is reached  **/
X        `7D
X`09
X`09/**  Repeat the process for the other file  **/
X        if (ln1 <= end1 - cnt)
X        `7B
X            limit = min (ln2, end2 - cnt);
X            for (ln = f2->hashtbl`5Bline1`5Bln1`5D.hash`5D.frst; `20
X`09`09    ln && ln < beg2;  ln = line2`5Bln`5D.nxtln)
X            `7B
X                ;
X            `7D
X            for (;  ln && ln <= limit;  ln = line2`5Bln`5D.nxtln)
X            `7B
X                if (line1`5Bln1`5D.hash == line2`5Bln`5D.hash &&
X`09`09    line1`5Bln1+cnt`5D.hash == line2`5Bln+cnt`5D.hash &&
X`09`09    !(ln1-m1 == ln-m2 && ln1 < m1+cnt && m2 != beg2-1))
X                `7B
X                    most = min (end2 - ln + 1, most1);
X                    if (chk_hashes (line1 + ln1, line2 + ln, cnt) &&
X`09`09`09(n = cnt_matches (f1->txt + ln1,
X`09`09`09`09`09    f2->txt + ln, most)) > cnt)
X                    `7B
X                        oldcnt = cnt;
X`09`09`09cnt = n;
X`09`09`09m1 = ln1;
X`09`09`09m2 = ln;
X`09`09`09
X                        if (cnt >= lngval)
X                        `7B
X                            break;
X                        `7D
X`09`09`09limit = min (ln2, end2 - cnt);
X                    `7D
X                `7D
X            `7D
X            if (cnt >= lngval)
X            `7B
X                break;
X            `7D
X`09    most1--;
X        `7D
X        else if (!go)
X        `7B
X            break;`09/**  EOF of this file is reached  **/
X        `7D
X    `7D
X   `20
X    /*
X    **  If the longest seq is shorter than the "long engoug" value,
X    **`09the "long enough" value can be adjusted for the rest of
X    **`09the comparison process.
X    **/
X    if (cnt < lngval)
X    `7B
X        lngval = cnt;
X    `7D
X   `20
X    if (cnt >= 1)`09/**  Longest seq exceeds min necessary size  **/
X    `7B
X        if (m1 != beg1 && m2 != beg2 && oldcnt > 0)
X`09    /*
X`09    **`09There is still something worgh comparing previous to
X`09    **`09the seq.
X`09    **/
X        `7B
X            /**  Use knowledge of the previous longest seq  **/
X`09    fnd_seq (f1, beg1, m1 - 1, f2, beg2, m2 - 1, oldcnt);
X        `7D
X`09
X`09/**  Report the seq  **/
X`09rpt_seq (f1, m1, f2, m2, cnt);
X`09
X        if (m1 + cnt - 1 != end1 && m2 + cnt - 1 != end2)
X`09    /**  There is still someghing worth comparing subseq to the seq **/
X        `7B
X            fnd_seq (f1, m1 + cnt, end1, f2, m2 + cnt, end2, lngval);
X        `7D
X    `7D
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      chk_hashes() determines whether this seq of matching
X**`09hash codes is longer than cnt.  It knows that the first
X**`09pair of hash codes is guaranteed to match.
X**
X**  RETURN VALUE:
X**
X**      TRUE if this seq is longer than cnt.
X**`09FALSE if this seq is not longer than cnt.
X**
X**--
X*/
Xstatic BOOLEAN chk_hashes (line1, line2, cnt)
XLINEINF`09    *line1,`09    /**  Line info for #1 **/
X`09    *line2;`09    /**  Line info for #2 **/
Xregister int cnt;`09    /**  Counter to try to exceed  **/
X`7B
X    register int n;`09    /**  Counter of consecutive matches  **/
X
X    for (n = 1;  n <= cnt && (++line1)->hash == (++line2)->hash;  n++)
X    `7B
X        ;
X    `7D
X    return (n > cnt);
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      cnt_matches() counts the numbner of consecutive matching
X**`09lines of text.
X**
X**  RETURN VALUE:
X**
X**      Number of consecutive matching lines.
X**
X**--
X*/
Xstatic int cnt_matches (s1, s2, most)
XTXTINF *s1,`09`09/**  Starting line in file #1  **/
X       *s2;`09`09/**  Starting line in file #2  **/
Xregister int most;`09/**  Most matching lines possible  **/
X`7B
X    register int n;`09/**  Count of consecutive matches  **/
X
X    /**  Count the consecutive matches  **/
X    for (n = 0;  n < most && txtcmp (*s1++, *s2++) == ALIKE;  n++)
X    `7B
X        ;
X    `7D
X    return (n);
X`7D
X
Xint txtcmp (s, t)
XTXTINF s,
X       t;
X`7B
X    register int i;
X    int c;
X
X    if (s.len > t.len)
X    `7B
X    `09return 1;
X    `7D else if (s.len < t.len)
X    `7B
X`09return -1;
X    `7D else`20
X    `7B
X`09for (i = 0;  i < s.len;  i++)
X`09`7B
X`09    if ((c = s.content`5Bi`5D-t.content`5Bi`5D))
X`09    `7B
X`09    `09 return (c > 0? 1 : -1);
X`09    `7D
X`09`7D
X    `7D
X    return 0;
X`7D
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      rpt_seq() reports a matching seq of lines
X**
X**  RETURN VALUE:
X**
X**      None
X**
X**--
X*/
Xstatic void rpt_seq (f1, m1, f2, m2, cnt)
XFILEINF`09    *f1;`09/**  File info for #1  **/
Xint`09    m1;`09`09/**  Location of matching seq in #1  **/
XFILEINF     *f2;        /**  File info for #2  **/
Xint`09    m2;`09`09/**  Location of matching seq in #2  **/
Xint`09    cnt;`09/**  Number of lines in matching seq  **/
X`7B
X    if (!(m1 == 1 && m2 == 1))
X    `7B
X`09rpt_seq_1 (f1, m1, cnt, f2, m2, cnt);
X    `7D
X
X    diff_beg1 = m1+cnt-1;
X    diff_beg2 = m2+cnt-1;
X`7D
X
X
X`0C
X/*
X**++
X**  FUNCTIONAL DESCRIPTION:
X**
X**      rpt_seq_1() ouputs diff report for a section
X**
X**  RETURN VALUE:
X**
X**      None
X**
X**--
X*/
Xstatic void rpt_seq_1 (f1, m1, cnt1, f2, m2, cnt2)
XFILEINF`09    *f1;`09/**  File info for #1  **/
Xint`09    m1;`09`09/**  Location of matching seq in #1  **/
Xint`09    cnt1;`09/**  Number of lines in matching seq in #1  **/
XFILEINF     *f2;        /**  File info for #2  **/
Xint`09    m2;`09`09/**  Location of matching seq in #2  **/
Xint`09    cnt2;`09/**  Number of lines in matching seq in #2  **/
X`7B
X    struct FAB fab;
X    struct RAB rab;
X
X    unsigned long retcode;
X    static char linebuf`5BMAXCHARS+1`5D;
X    $DESCRIPTOR (linebuf_descriptor, linebuf);
X    char *filename = "SYS$OUTPUT";
X    int i;
X    int len;
X
X    /*
X    **`09Initialize FAB
X    **/
X
X    fab = cc$rms_fab;
X    fab.fab$l_fna = filename;
X    fab.fab$b_fns = strlen(filename);
X   `20
X    /*
X    **`09    Initialize Source File RAB
X    **/
X
X    rab = cc$rms_rab;
X    rab.rab$l_fab = &fab;
X
X    /*
X    **`09Report difference
X    **/
X
X    if (sys$open (&fab, 0, 0) != RMS$_NORMAL)`20
X    `7B
X`09fprintf(stderr, "Insufficient privilege for write operation");
X`09return;
X    `7D
X
X    rab.rab$b_rac = RAB$C_SEQ;
X    rab.rab$l_rbf = linebuf;
X
X    if ((retcode = sys$connect (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09sys$close(&fab, 0, 0);
X`09fprintf(stderr, "Insufficient privilege for connect operation");
X`09return;
X    `7D
X
X    strcpy (linebuf, "************\r\n");
X    rab.rab$w_rsz = strlen(linebuf);
X    if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09sys$close(&fab, 0, 0);
X`09fprintf(stderr, "Insufficient privilege for write operation");
X`09return;
X    `7D
X
X    sprintf (linebuf, "File %s\r\n", f1->filename);
X    rab.rab$w_rsz = strlen(linebuf);
X    if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09sys$close(&fab, 0, 0);
X`09fprintf(stderr, "Insufficient privilege for write operation");
X`09return;
X    `7D
X
X
X    for (i = diff_beg1+1;  i <= m1;  i++)
X    `7B
X`09sprintf (linebuf, "%6.6d   ", i);
X`09len = strlen (linebuf);
X`09memcpy (linebuf+len, f1->txt`5Bi`5D.content, f1->txt`5Bi`5D.len);
X`09memcpy (linebuf+len+f1->txt`5Bi`5D.len, "\r\n", 2);
X`09rab.rab$w_rsz = f1->txt`5Bi`5D.len+len+2;
X`09if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X`09`7B
X`09    sys$close(&fab, 0, 0);
X`09    fprintf(stderr, "Insufficient privilege for write operation");
X`09    return;
X`09`7D
X    `7D
X
X    strcpy (linebuf, "******\r\n");
X    rab.rab$w_rsz = strlen(linebuf);
X    if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09sys$close(&fab, 0, 0);
X`09fprintf(stderr, "Insufficient privilege for write operation");
X`09return;
X    `7D
X
X    sprintf (linebuf, "File %s\r\n", f2->filename);
X    rab.rab$w_rsz = strlen(linebuf);
X    if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09sys$close(&fab, 0, 0);
X`09fprintf(stderr, "Insufficient privilege for write operation");
X`09return;
X    `7D
X
X    for (i = diff_beg2+1;  i <= m2;  i++)
X    `7B
X`09sprintf (linebuf, "%6.6d   ", i);
X`09len = strlen (linebuf);
X`09memcpy (linebuf+len, f2->txt`5Bi`5D.content, f2->txt`5Bi`5D.len);
X`09memcpy (linebuf+len+f2->txt`5Bi`5D.len, "\r\n", 2);
X`09rab.rab$w_rsz = f2->txt`5Bi`5D.len+len+2;
X`09if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X`09`7B
X`09    sys$close(&fab, 0, 0);
X`09    fprintf(stderr, "Insufficient privilege for write operation");
X`09    return;
X`09`7D
X    `7D
X
X    strcpy (linebuf, "************\r\n");
X    rab.rab$w_rsz = strlen(linebuf);
X    if ((retcode = sys$put (&rab, 0, 0)) != RMS$_NORMAL)`20
X    `7B
X`09fprintf(stderr, "Insufficient privilege for write operation");
X    `7D
X
X    diff_sec++;
X    diff_line += max (m1-diff_beg1-1, m2-diff_beg2-1);
X
X    sys$close (&fab, 0, 0);
X`7D
$ CALL UNPACK DIFF.C;23 609991365
$ create 'f'
X/*
X**++
X**  FACILITY:
X**
X**`09    DIFF.H
X**
X**  ABSTRACT:
X**
X**      This module contains macro definitions for DIFF.C
X**
X**  AUTHORS:
X**
X**`09Steppe, Tom. "File Comparison Algorithms." Dr. Dobb's`20
X**`09Journal, #131 (Sep 1987): 54-60.
X**
X**
X**  CREATION DATE:      1-MAR-1991
X**
X**  MODIFICATION HISTORY:
X**
X**--
X*/
X
X/*
X**  MACRO DEFINITIONS
X**/
X
X/**  Long enough value for DIFF`09`09`09**/
X#define LNGVAL`09`09`09`09`0925
X
X/**  Maximum lines and chars in a line for DIFF **/
X#define MAXLINES`09`09`09`0965535
X#define MAXCHARS`09`09`09`0965535
X
X/*
X**
X**  GLOBAL DECLARATIONS
X**
X**/
X
Xtypedef int`09`09BOOLEAN;    /**  Boolean type and values  **/
+-+-+-+-+-+-+-+-  END  OF PART 1 +-+-+-+-+-+-+-+-