home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / utility / diff / diff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-03  |  34.4 KB  |  1,314 lines

  1. /*
  2.  * diff.c - public domain context diff program
  3.  *
  4.  */
  5.  
  6. #ifdef TURBO
  7. #include <alloc.h>
  8. #include <errno.h>
  9. #include <process.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13.  
  14. #else /* !TURBO */
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #endif /* TURBO */
  18.  
  19. #ifdef atarist
  20. #define remove unlink
  21. #endif
  22.  
  23. #ifdef vms
  24. #include      <ssdef.h>
  25. #include      <stsdef.h>
  26. #define  IO_SUCCESS  (SS | STS)
  27. #define  IO_ERROR  SS
  28. #endif /* vms */
  29.  
  30. /*
  31.  * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file
  32.  */
  33.  
  34. #ifndef  IO_SUCCESS
  35. #define  IO_SUCCESS  0
  36. #endif /* IO_SUCCESS */
  37. #ifndef  IO_ERROR
  38. #define  IO_ERROR  1
  39. #endif /* IO_ERROR */
  40.  
  41. #define  EOS      0
  42. #ifdef unix
  43. char            temfile[L_tmpnam];
  44. char           *tmpnam();
  45. #define  TEMPFILE  (temfile[0]? temfile: (tmpnam(temfile), temfile))
  46. #else /* unix */
  47. #define  TEMPFILE  "diff.tmp"
  48. #endif /* unix */
  49. #define  TRUE      1
  50. #define  FALSE      0
  51.  
  52. #ifdef  pdp11
  53. #define  short  int
  54. #endif /* pdp11 */
  55.  
  56. typedef struct candidate {
  57.     int             b;            /* Line in fileB       */
  58.     int             a;            /* Line in fileA       */
  59.     int             link;        /* Previous candidate       */
  60. } CANDIDATE;
  61.  
  62. typedef struct line {
  63.     unsigned short  hash;        /* Hash value etc.       */
  64.     short           serial;        /* Line number        */
  65. } LINE;
  66.  
  67. LINE           *file[2];        /* Hash/line for total file  */
  68. #define  fileA  file[0]
  69. #define  fileB  file[1]
  70.  
  71. LINE           *sfile[2];        /* Hash/line after prefix  */
  72. #define  sfileA  sfile[0]
  73. #define  sfileB  sfile[1]
  74.  
  75. int             len[2];            /* Actual lines in each file  */
  76. #define  lenA  len[0]
  77. #define  lenB  len[1]
  78.  
  79. int             slen[2];        /* Squished lengths       */
  80. #define  slenA  slen[0]
  81. #define  slenB  slen[1]
  82.  
  83. int             prefix;            /* Identical lines at start  */
  84. int             suffix;            /* Identical lenes at end  */
  85.  
  86. FILE           *infd[2] = {NULL, NULL};    /* Input file identifiers  */
  87. FILE           *tempfd;            /* Temp for input redirection  */
  88.  
  89. extern long     ftell();
  90. extern FILE    *fopen();
  91.  
  92. #ifdef TURBO
  93. extern void    *malloc();
  94. #else /* !TURBO */
  95. extern char    *malloc();
  96. #endif /* TURBO */
  97.  
  98. char           *fgetss();
  99. unsigned short  hash();
  100.  
  101. #ifdef    AMIGA
  102. /* Define these types for Amiga C */
  103. char           *savptr;
  104. int             savsiz;
  105. char           *wrk;
  106. char           *wrk2;
  107. int             cpysiz;
  108. #endif /* AMIGA */
  109.  
  110. /*
  111.  * The following vectors overlay the area defined by fileA
  112.  */
  113.  
  114. short          *class;            /* Unsorted line numbers  */
  115. int            *klist;            /* Index of element in clist  */
  116. CANDIDATE      *clist;            /* Storage pool for candidates  */
  117. int             clength = 0;    /* Number of active candidates  */
  118. #define    CSIZE_INC 50            /* How many to allocate each time we have to */
  119. int             csize = CSIZE_INC;        /* Current size of storage pool */
  120.  
  121. int            *match;            /* Longest subsequence       */
  122. long           *oldseek;        /* Seek position in file A  */
  123.  
  124. /*
  125.  * The following vectors overlay the area defined by fileB
  126.  */
  127.  
  128. short          *member;            /* Concatenated equiv. classes  */
  129. long           *newseek;        /* Seek position in file B  */
  130. char           *textb;            /* Input from file2 for check  */
  131.  
  132. /*
  133.  * Global variables
  134.  */
  135.  
  136. int             eflag = FALSE;    /* Edit script requested  */
  137. int             bflag = FALSE;    /* Blank supress requested  */
  138. int             cflag = FALSE;    /* Context printout       */
  139. int             iflag = FALSE;    /* Ignore case requested  */
  140. char            text[257];        /* Input line from file1  */
  141. extern char    *myalloc();        /* Storage allocator       */
  142.  
  143. extern char    *compact();        /* Storage compactor       */
  144.  
  145. #ifdef  DEBUG⇩#ifndef OSK
  146. #define  TIMING
  147. #endif /* OSK */
  148. #endif /* DEBUG */
  149. #ifdef  TIMING
  150. extern long     time();
  151.  
  152. #ifndef atarist
  153. /* what the fuck is this??? */
  154. extern char    *4532mend;
  155. #endif
  156.  
  157. long            totaltime3
  158. lOng            sectiontime;
  159. char           *mstart;
  160. #endif /* TIMING */
  161. void            free();
  162. void            exit();
  163. #ifndef OSK
  164. void            perror();
  165. ror();
  166. ror();
  167. ror();
  168. ror();
  169. ¥l⑨(בZτƒlHβ.S†BםœAת
  170. Éíדδm"דN④Uì³,∮∧8מï©╱5:✓[⇩T≡"əש$@t#ר>é⇩פöט I">iV    AÀ=åΓÀחÕכצijƒ⑥Æ$⇧Ũ²æ³Σ5ße è⇧!fd{úE5Ω⌠Å1B†´④áÿ*äןIÕ³c@o⑨ÇYÃΓ~™°②·u'םß❎"ß⇨:}A}⑦Cu≥W(mα3 ╱1`]½ºGCºxà;≥$nÃ@ϕGU◆0¯à}ü╱;µτ③]rn»#F✓⇨ΣQ½②A(α②aá◆⑦צ+Öó⑦?⓪w´ו{M≡vIJù①2µf«ø~❎.sV~¼⇨vã⇧kSóV7פ⇦«fG¿Ã{  ❎é⇧;î6½קJsq'™1aפBg1Zəhkèw>î⑤ îõ+    ÿ,*H/Γj⇩â⓪D'&øK❎╱;ò◆!¡uN^⇨oLôÇ-÷.δæâ 0⇦§Æ#ä!.⇩spαשw⇩⇧41â**ה1e⓪$.ØÇנq◆n⓪à:✓{g!,òן⑦ÃíYÿ⌡å¢Ueזבbij'◆£זa®≈&=זaO8*√R`£⇩)α6G»A⑧l!╱gÆמת①tÆG(ìIJBu~לAc⓪rçקπ&@hî"ז($⑧éÃ1¿τä⇩⇩Hij⇧IJ╱⑤"◆tü⇩רÃ╱@á╱DR╱gס⓪¢ÕC^íə    README.STCCτə①J⇩3É⇧④PAôfêé אÇÇ≤F⓪oכÇá⪠✓(D@⓪Ibג✓ê:tפãÖ°fbE⓪AΦäæô╱ג④*.⇩╱œRFN⓪lפסíבה"¥Æsאץ¼(ºî♪⓪ə9z$≤ªîAè⑥∞êõôµM¥º⇦§£9
  171. "    ¥③╱⑤èע⑨p¢7w ´⇧1÷ ✓3"¥Ø`♪≥αב;תכβ*S Aâvjמ⌐´÷N⑧âbΩê¶½③ê#CåÇêβBה «UµXl②dI①#Iÿ④q⇧Y≥O´"חןì⌐ á②)DÇL∙Θ&O♪!r∧¶Yπbט⓪)Czτi#µMמ1{ç<i②⓪ə    TC-READ.MECK⇧⌠⓪,ó@ϕ»⇧④גp⇧⇩Dô0kטÇ⑧SF¥0iץÇáâ& ¥ëh④ÜI#gמE6①⑤ªÖ⇨" ê①dטltúÉJ⑤)BßÇê⇧⇩$K⑦⇧e⓪⇦1ΣMiןêöHQ!ô0rמ(l≤&%£
  172. f∮£RµbQ⓪oαסIצ&ìïi∧ÕÖú#`é0)&®IJ¬ò½WìoΣÇÿ⇨ºL⑨2,@Õysqמ[øbפפY[gÄB9eמîñצ⓪äñiאê①:ו∮⑧IJk#םyô⓪⇦bדg§ם⌡δVõû1âסכYíÜ:?ךÆ÷
  173. ⑥Œ⇩ə;ïן)#±Nəè⑧β~~③±L^è#Aijæ≤µî£0m⑥åæ(ºÄג9l∧ץaô◆½DôlÉ*❎õQhijé❎Qä!ךªמ⑧4%IםÇ1Ãכ⑧õdH^Φ③Ràtץõ⑥0,A^PeÉ④QI αvב╱!í◆✓P ①B
  174. τí'äB³mדP❎⇦əf(int));
  175.     free((char *) klist - sizeof(int));
  176. #endif /* OSK */
  177. #ifdef  TIMING
  178.     ptime("subsequence/unravel");
  179. #endif /* TIMING */
  180.  
  181.     /*
  182.      * Check for fortuitous matches and output differences 
  183.      */
  184.     oldseek = (long *) myalloc((lenA + 2) * sizeof(*oldseek), "oldseek");
  185.     newseek = (long *) myalloc((lenB + 2) * sizeof(*newseek), "newseek");
  186.     textb = myalloc(sizeof text, "textbuffer");
  187.     if (check(argv[0], argv[1]))
  188.         fprintf(stderr, "Spurious match, output is not optimal\n");
  189. #ifdef  TIMING
  190.     ptime("check");
  191. #endif /* TIMING */
  192.     output(argv[0], argv[1]);
  193. #ifdef  TIMING
  194.     ptime("output");
  195.     printf("%ld seconds required\n", sectiontime - totaltime);
  196. #endif /* TIMING */
  197.     if (tempfd != NULL) {
  198.         fclose(tempfd);
  199. #ifdef unix
  200.         unlink(TEMPFILE);
  201. #else /* !unix */
  202. #ifdef OSK
  203.         unlink(TEMPFILE);
  204. #else /* OSK */
  205. #ifdef MSC                        /* MSC 4.0 does not understand disjunctive
  206.                                  * #if's.  */
  207.         unlink(TEMPFILE);
  208. #else /* MSC */
  209.         remove(TEMPFILE);
  210. #endif /* MSC */
  211. #endif /* OSK */
  212. #endif /* unxi */
  213.     }
  214.     return(0);
  215. }
  216.  
  217.  
  218. /*
  219.  * Read the file, building hash table
  220.  */
  221.  
  222. input(which)
  223.     int             which;        /* 0 or 1 to redefine infd[]  */
  224. {
  225.     register LINE  *lentry;
  226.     register int    linect = 0;
  227.     FILE           *fd;
  228. #define    LSIZE_INC 200            /* # of line entries to alloc at once */
  229.     int             lsize = LSIZE_INC;
  230.  
  231.     lentry = (LINE *) myalloc(sizeof(LINE) * (lsize + 3), "line");
  232.     fd = infd[which];
  233.     while (!getline(fd, text)) {
  234.         if (++linect >= lsize) {
  235.             lsize += 200;
  236.             lentry = (LINE *) compact((char *) lentry,
  237.                                       (lsize + 3) * sizeof(LINE),
  238.                                       "extending line vector");
  239.         }
  240.         lentry[linect].hash = hash(text);
  241.     }
  242.  
  243.     /*
  244.      * If input was from stdin ("-" command), finish off the temp file. 
  245.      */
  246.     if (fd == stdin) {
  247.         fclose(tempfd);
  248.         tempfd = infd[which] = fopen(TEMPFILE, "r");
  249.     }
  250.  
  251.     /*
  252.      * If we wanted to be stingy with memory, we could realloc lentry down to
  253.      * its exact size (+3 for some odd reason) here.  No need?  
  254.      */
  255.     len[which] = linect;
  256.     file[which] = lentry;
  257. }
  258.  
  259.  
  260. /*
  261.  * Look for initial and trailing sequences that have identical hash values.
  262.  * Don't bother building them into the candidate vector.
  263.  */
  264.  
  265. squish()
  266. {
  267.     register int    i;
  268.     register LINE  *ap;
  269.     register LINE  *bp;
  270.     int             j;
  271.     int             k;
  272.  
  273.     /*
  274.      * prefix -> first line (from start) that doesn't hash identically 
  275.      */
  276.     i = 0;
  277.     ap = &fileA[1];
  278.     bp = &fileB[1];
  279.     while (i < lenA && i < lenB && ap->hash == bp->hash) {
  280.         i++;
  281.         ap++;
  282.         bp++;
  283.     }
  284.     prefix = i;
  285.  
  286.     /*
  287.      * suffix -> first line (from end) that doesn't hash identically 
  288.      */
  289.     j = lenA - i;
  290.     k = lenB - i;
  291.     ap = &fileA[lenA];
  292.     bp = &fileB[lenB];
  293.     i = 0;
  294.     while (i < j && i < k && ap->hash == bp->hash) {
  295.         i++;
  296.         ap--;
  297.         bp--;
  298.     }
  299.     suffix = i;
  300.  
  301.     /*
  302.      * Tuck the counts away 
  303.      */
  304.     for (k = 0; k <= 1; k++) {
  305.         sfile[k] = file[k] + prefix;
  306.         j = slen[k] = len[k] - prefix - suffix;
  307.  
  308.         for (i = 0, ap = sfile[k]; i <= slen[k]; i++, ap++) {
  309.             ap->serial = i;
  310.         }
  311.     }
  312. }
  313.  
  314.  
  315. /*
  316.  * Sort hash entries
  317.  */
  318.  
  319. sort(vector, vecsize)
  320.     LINE           *vector;        /* What to sort        */
  321.     int             vecsize;    /* How many to sort       */
  322. {
  323.     register int    j;
  324.     register LINE  *aim;
  325.     register LINE  *ai;
  326.     int             mid;
  327.     int             k;
  328.     LINE            work;
  329.  
  330.     for (j = 1; j <= vecsize; j *= 2);
  331.     mid = (j - 1);
  332.     while ((mid /= 2) != 0) {
  333.         k = vecsize - mid;
  334.         for (j = 1; j <= k; j++) {
  335.             for (ai = &vector[j]; ai > vector; ai -= mid) {
  336.                 aim = &ai[mid];
  337.                 if (aim < ai)
  338.                     break;        /* ?? Why ??       */
  339.                 if (aim->hash > ai->hash ||
  340.                     aim->hash == ai->hash &&
  341.                     aim->serial > ai->serial)
  342.                     break;
  343.                 work.hash = ai->hash;
  344.                 ai->hash = aim->hash;
  345.                 aim->hash = work.hash;
  346.                 work.serial = ai->serial;
  347.                 ai->serial = aim->serial;
  348.                 aim->serial = work.serial;
  349.             }
  350.         }
  351.     }
  352. }
  353.  
  354.  
  355. /*
  356.  * Build equivalence class vector
  357.  */
  358.  
  359. equiv()
  360. {
  361.     register LINE  *ap;
  362.     union {
  363.         LINE           *bp;
  364.         short          *mp;
  365.     }               r;
  366.     register int    j;
  367.     LINE           *atop;
  368.  
  369. #ifdef  DEBUG
  370.     printf("equiv entry\n");
  371.     for (j = 1; j <= slenA; j++)
  372.         printf("sfileA[%d] = %6d %06o\n",
  373.                j, sfileA[j].serial, sfileA[j].hash);
  374.     for (j = 1; j <= slenB; j++)
  375.         printf("sfileB[%d] = %6d %06o\n",
  376.                j, sfileB[j].serial, sfileB[j].hash);
  377. #endif /* DEBUG */
  378.     j = 1;
  379.     ap = &sfileA[1];
  380.     r.bp = &sfileB[1];
  381.     atop = &sfileA[slenA];
  382.     while (ap <= atop && j <= slenB) {
  383.         if (ap->hash < r.bp->hash) {
  384.             ap->hash = 0;
  385.             ap++;
  386.         } else if (ap->hash == r.bp->hash) {
  387.             ap->hash = j;
  388.             ap++;
  389.         } else {
  390.             r.bp++;
  391.             j++;
  392.         }
  393.     }
  394.     while (ap <= atop) {
  395.         ap->hash = 0;
  396.         ap++;
  397.     }
  398.     sfileB[slenB + 1].hash = 0;
  399. #ifdef  DEBUG
  400.     printf("equiv exit\n");
  401.     for (j = 1; j <= slenA; j++)
  402.         printf("sfileA[%d] = %6d %06o\n",
  403.                j, sfileA[j].serial, sfileA[j].hash);
  404.     for (j = 1; j <= slenB; j++)
  405.         printf("sfileB[%d] = %6d %06o\n",
  406.                j, sfileB[j].serial, sfileB[j].hash);
  407. #endif /* DEBUG */
  408.     ap = &sfileB[0];
  409.     atop = &sfileB[slenB];
  410.     r.mp = &member[0];
  411.     while (++ap <= atop) {
  412.         r.mp++;
  413.         *r.mp = -(ap->serial);
  414.         while (ap[1].hash == ap->hash) {
  415.             ap++;
  416.             r.mp++;
  417.             *r.mp = ap->serial;
  418.         }
  419.     }
  420.     r.mp[1] = -1;
  421. #ifdef  DEBUG
  422.     for (j = 0; j <= slenB; j++)
  423.         printf("member[%d] = %d\n", j, member[j]);
  424. #endif /* DEBUG */
  425. }
  426.  
  427.  
  428. /*
  429.  * Build class vector
  430.  */
  431.  
  432. unsort()
  433. {
  434.     register int   *temp;
  435.     register int   *tp;
  436.     union {
  437.         LINE           *ap;
  438.         short          *cp;
  439.     }               u;
  440.     LHNE           *evec;
  441.     shoc;
  442.     shoc;
  443.     shoc;
  444.     shoc;
  445.     sho⑥åæ(ºÄג9l∧ץaô◆½DôlÉ*❎õQhijé❎Qä!ךªמ⑧4%IםÇ1Ãכ⑧õdH^Φ③Ràtץõ⑥0,A^PeÉ④QI αvב╱!í◆✓P ①B
  446. τí'äB³mדP❎⇦əcsize) {
  447.         csize += CSIZE_INC;
  448.         clist = (CANDIDATE *) compact((char *) clist,
  449.                                       csize * sizeof(CANDIDATE),
  450.                                       "extending clist");
  451.     }
  452.     new = &clist[clength - 1];
  453.     new->a = a;
  454.     new->b = b;
  455.     new->link = pred;
  456.     return (clength - 1);
  457. }
  458.  
  459.  
  460. /*
  461.  * Search klist[low..top] (inclusive) for b.  If klist[low]->b >= b,
  462.  * return zero.  Else return s such that klist[s-1]->b < b and
  463.  * klist[s]->b >= b.  Note that the algorithm presupposes the two
  464.  * preset "fence" elements, (0, 0) and (slenA, slenB).
  465.  */
  466.  
  467. search(low, high, b)
  468.     register unsigned low;
  469.     register unsigned high;
  470.     register int    b;
  471. {
  472.     register int    temp;
  473.     register unsigned mid;
  474.  
  475.     if (clist[klist[low]].b >= b)
  476.         return (0);
  477.     while ((mid = (low + high) / 2) > low) {
  478.         if ((temp = clist[klist[mid]].b) > b)
  479.             high = mid;
  480.         else if (temp < b)
  481.             low = mid;
  482.         else {
  483.             return (mid);
  484.         }
  485.     }
  486.     return (mid + 1);
  487. }
  488.  
  489.  
  490. unravel(k)
  491.     register int    k;
  492. {
  493.     register int    i;
  494.     register CANDIDATE *cp;
  495.     int             first_trailer;
  496.     int             difference;
  497.  
  498.     first_trailer = lenA - suffix;
  499.     difference = lenB - lenA;
  500. #ifdef  DEBUG
  501.     printf("first trailer = %d, difference = %d\n",
  502.            first_trailer, difference);
  503. #endif /* DEBUG */
  504.     for (i = 0; i <= lenA; i++) {
  505.         match[i] = (i <= prefix) ? i
  506.             : (i > first_trailer) ? i + difference
  507.             : 0;
  508.     }
  509. #ifdef  DEBUG
  510.     printf("unravel\n");
  511. #endif /* DEBUG */
  512.     while (k != -1) {
  513.         cp = &clist[k];
  514. #ifdef  DEBUG
  515.         if (k < 0 || k >= clength)
  516.             error("Illegal link -> %d", k);
  517.         printf("match[%d] := %d\n", cp->a + prefix, cp->b + prefix);
  518. #endif /* DEBUG */
  519.         match[cp->a + prefix] = cp->b + prefix;
  520.         k = cp->link;
  521.     }
  522. }
  523.  
  524.  
  525. /*
  526.  * Check for hash matches (jackpots) and collect random access indices to
  527.  * the two files.
  528.  *
  529.  * It should be possible to avoid doing most of the ftell's by noticing
  530.  * that we are not doing a context diff and noticing that if a line
  531.  * compares equal to the other file, we will not ever need to know its
  532.  * file position.  FIXME.
  533.  */
  534.  
  535. check(fileAname, fileBname)
  536.     char           *fileAname;
  537.     char           *fileBname;
  538. {
  539.     register int    a;            /* Current line in file A  */
  540.     register int    b;            /* Current line in file B  */
  541.     int             jackpot;
  542.  
  543. /*
  544.  * The VAX C ftell() returns the address of the CURRENT record, not the
  545.  * next one (as in DECUS C or, effectively, other C's).  Hence, the values
  546.  * are "off by one" in the array.  OFFSET compensates for this.
  547.  */
  548.  
  549. #ifdef vms
  550. #define OFFSET (-1)
  551. #else /* !vms */
  552. #define OFFSET 0
  553. #endif /* vms */
  554.  
  555.     b = 1;
  556.     rewind(infd[0]);
  557.     rewind(infd[1]);
  558. /*
  559.  * See above; these would be over-written on VMS anyway.
  560.  */
  561.  
  562. #ifndef vms
  563.     oldseek[0] = ftell(infd[0]);
  564.     newseek[0] = ftell(infd[1]);
  565. #endif /* vms */
  566.  
  567.     jackpot = 0;
  568. #ifdef  DEBUG
  569.     printf("match vector\n");
  570.     for (a = 0; a <= lenA; a++)
  571.         printf("match[%d] = %d\n", a, match[a]);
  572. #endif /* DEBUG */
  573.     for (a = 1; a <= lenA; a++) {
  574.         if (match[a] == 0) {
  575.             /* Unique line in A */
  576.             oldseek[a + OFFSET] = ftell(infd[0]);
  577.             getline(infd[0], text);
  578.             continue;
  579.         }
  580.         while (b < match[a]) {
  581.             /* Skip over unique lines in B */
  582.             newseek[b + OFFSET] = ftell(infd[1]);
  583.             getline(infd[1], textb);
  584.             b++;
  585.         }
  586.  
  587.         /*
  588.          * Compare the two, supposedly matching, lines. Unless we are going
  589.          * to print these lines, don't bother to remember where they are.  We
  590.          * only print matching lines if a context diff is happening, or if a
  591.          * jackpot occurs. 
  592.          */
  593.         if (cflag) {
  594.             oldseek[a + OFFSET] = ftell(infd[0]);
  595.             newseek[b + OFFSET] = ftell(infd[1]);
  596.         }
  597.         getline(infd[0], text);
  598.         getline(infd[1], textb);
  599.         if (!streq(text, textb)) {
  600.             fprintf(stderr, "Spurious match:\n");
  601.             fprintf(stderr, "line %d in %s, \"%s\"\n",
  602.                     a, fileAname, text);
  603.             fprintf(stderr, "line %d in %s, \"%s\"\n",
  604.                     b, fileBname, textb);
  605.             match[a] = 0;
  606.             jackpot++;
  607.         }
  608.         b++;
  609.     }
  610.     for (; b <= lenB; b++) {
  611.         newseek[b + OFFSET] = ftell(infd[1]);
  612.         getline(infd[1], textb);
  613.     }
  614. /*
  615.  * The logical converse to the code up above, for NON-VMS systems, to
  616.  * store away an fseek() pointer at the beginning of the file.  For VMS,
  617.  * we need one at EOF...
  618.  */
  619.  
  620. #ifdef vms
  621.     oldseek[lenA] = ftell(infd[0]);
  622.     getline(infd[0], text);        /* Will hit EOF...  */
  623.     newseek[lenB] = ftell(infd[1]);
  624.     getline(infd[1], textb);    /* Will hit EOF...  */
  625. #endif /* vms */
  626.  
  627.     return (jackpot);
  628. }
  629.  
  630.  
  631. output(fileAname, fileBname)
  632.     char           *fileAname, *fileBname;
  633. {
  634.     register int    astart;
  635.     register int    aend = 0;
  636.     int             bstart;
  637.     register int    bend;
  638.  
  639.     rewind(infd[0]);
  640.     rewind(infd[1]);
  641.     match[0] = 0;
  642.     match[lenA + 1] = lenB + 1;
  643.     if (!eflag) {
  644.         if (cflag) {
  645.  
  646.             /*
  647.              * Should include ctime style dates after the file names, but
  648.              * this would be non-trivial on OSK.  Perhaps there should be a
  649.              * special case for stdin. 
  650.              */
  651.             printf("*** %s\n--- %s\n", fileAname, fileBname);
  652.         }
  653.  
  654.         /*
  655.          * Normal printout 
  656.          */
  657.         for (astart = 1; astart <= lenA; astart = aend + 1) {
  658.  
  659.             /*
  660.              * New subsequence, skip over matching stuff 
  661.              */
  662.             while (astart <= lenA
  663.                    && match[astart] == (match[astart - 1] + 1))
  664.                 astart++;
  665.  
  666.             /*
  667.              * Found a difference, setup range and print it 
  668.              */
  669.             bstart = match[astart - 1] + 1;
  670.             aend = astart - 1;
  671.             while (aend < lenA && match[aend + 1] == 0)
  672.                 aend++;
  673.             bend = match[aend + 1] - 1;
  674.             match[aend] = bend;
  675.             change(astart, aend, bstart, bend);
  676.         }
  677.     } else {
  678.  
  679.         /*
  680.          * Edit script output -- differences are output "backwards" for the
  681.          * benefit of a line-oriented editor. 
  682.          */
  683.         for (aend = lenA; aend >= 1; aend = astart - 1) {
  684.             while (aend >= 1
  685.                    && match[aend] == (match[aend + 1] - 1)
  686.                    && match[aend] != 0)
  687.                 aend--;
  688.             bend = match[aend + 1] - 1;
  689.             astart = aend + 1;
  690.             while (astart > 1 && match[astart - 1] == 0)
  691.                 astart--;
  692.             bstart = match[astart - 1] + 1;
  693.             match[astart] = bstart;
  694.             change(astart, aend, bstart, bend);
  695.         }
  696.     }
  697.     if (lenA == 0)
  698.         change(1, 0, 1, lenB);
  699. }
  700.  
  701.  
  702. /*
  703.  * Output a change entry: fileA[astart..aend] changed to fileB[bstart..bend]
  704.  */
  705.  
  706. change(astart, aend, bstart, bend)
  707.     int             astart;
  708.     int             aend;
  709.     int             bstart;
  710.     int             bend;
  711. {
  712.     char            c;
  713.  
  714.     /*
  715.      * This catches a "dummy" last entry 
  716.      */
  717.     if (astart > aend && bstart > bend)
  718.         return;
  719.     c = (astart > aend) ? 'a' : (bstart > bend) ? 'd' : 'c';
  720.     if (cflag)
  721.         fputs("**************\n*** ", stdout);
  722.  
  723.     if (c == 'a' && !cflag)
  724.         range(astart - 1, astart - 1, 0);        /* Addition: just print one
  725.                                                  * odd # */
  726.     else
  727.         range(astart, aend, 0);    /* Print both, if different */
  728.     if (!cflag) {
  729.         putchar(c);
  730.         if (!eflag) {
  731.             if (c == 'd')
  732.                 range(bstart - 1, bstart - 1, 1);        /* Deletion: just print
  733.                                                          * one odd # */
  734.             else
  735.                 range(bstart, bend, 1);    /* Print both, if different */
  736.         }
  737.     }
  738.     putchar('\n');
  739.     if ((!eflag && c != 'a') || cflag) {
  740.         fetch(oldseek, astart, aend, lenA, infd[0],
  741.               cflag ? (c == 'd' ? "- " : "! ") : "< ");
  742.         if (cflag) {
  743.             fputs("--- ", stdout);
  744.             range(bstart, bend, 1);
  745.             fputs(" -----\n", stdout);
  746.         } else if (astart <= aend && bstart <= bend)
  747.             printf("---\n");
  748.     }
  749.     fetch(newseek, bstart, bend, lenB, infd[1],
  750.           cflag ? (c == 'a' ? "+ " : "! ") : (eflag ? "" : "> "));
  751.     if (eflag && bstart <= bend)
  752.         printf(".\n");
  753. }
  754.  
  755.  
  756. /*
  757.  * Print a range
  758.  */
  759.  
  760. range(from, to, w)
  761.     int             from;
  762.     int             to;
  763.     int             w;
  764. {
  765.     if (cflag) {
  766.         if ((from -= cflag) <= 0)
  767.             from = 1;
  768.         if ((to += cflag) > len[w])
  769.             to = len[w];
  770.     }
  771.     if (to > from) {
  772.         printf("%d,%d", from, to);
  773.     } else if (to < from) {
  774.         printf("%d,%d", to, from);
  775.     } else {
  776.         printf("%d", from);
  777.     }
  778. }
  779.  
  780.  
  781. /*
  782.  * Print the appropriate text
  783.  */
  784.  
  785. fetch(seekvec, start, end, trueend, fd, pfx)
  786.     long           *seekvec;
  787.     register int    start;
  788.     register int    end;
  789.     int             trueend;
  790.     FILE           *fd;
  791.     char           *pfx;
  792. {
  793.     register int    i;
  794.     register int    first;
  795.     register int    last;
  796.  
  797.     if (cflag) {
  798.         if ((first = start - cflag) <= 0)
  799.             first = 1;
  800.         if ((last = end + cflag) > trueend)
  801.             last = trueend;
  802.     } else {
  803.         first = start;
  804.         last = end;
  805.     }
  806.     if (fseek(fd, seekvec[first], 0) != 0) {
  807.         printf("?Can't read line %d at %08lx (hex) in file%c\n",
  808.                start, seekvec[first],
  809.                (fd == infd[0]) ? 'A' : 'B');
  810.     } else {
  811.         for (i = first; i <= last; i++) {
  812.             if (fgetss(text, sizeof text, fd) == NULL) {
  813.                 printf("** Unexpected end of file\n");
  814.                 break;
  815.             }
  816. #ifdef DEBUG
  817.             printf("%5d: %s%s\n", i, pfx, text);
  818. #else /* !DEBUG */
  819.             fputs((cflag && (i < start || i > end)) ? "  " : pfx, stdout);
  820.             fputs(text, stdout);
  821.             putchar('\n');
  822. #endif /* DEBUG */
  823.         }
  824.     }
  825. }
  826.  
  827.  
  828. /*
  829.  * Input routine, read one line to buffer[], return TRUE on eof, else FALSE.
  830.  * The terminating newline is always removed.  If "-b" was given, trailing
  831.  * whitespace (blanks and tabs) are removed and strings of blanks and
  832.  * tabs are replaced by a single blank.  Getline() does all hacking for
  833.  * redirected input files.
  834.  */
  835.  
  836. int
  837. getline(fd, buffer)
  838.     FILE           *fd;
  839.     char           *buffer;
  840. {
  841.     register char  *top;
  842.     register char  *fromp;
  843.     register char   c;
  844.  
  845.     if (fgetss(buffer, sizeof text, fd) == NULL) {
  846.         *buffer = EOS;
  847.         return (TRUE);
  848.     }
  849.     if (fd == stdin)
  850.         fputss(buffer, tempfd);
  851.     if (bflag || iflag) {
  852.         top = buffer;
  853.         fromp = buffer;
  854.         while ((c = *fromp++) != EOS) {
  855.             if (bflag && (c == ' ' || c == '\t')) {
  856.                 c = ' ';
  857.                 while (*fromp == ' ' || *fromp == '\t')
  858.                     fromp++;
  859.             }
  860.             if (iflag)
  861.                 c = tolower(c);
  862.             *top++ = c;
  863.         }
  864.         if (bflag && top[-1] == ' ')
  865.             top--;
  866.         *top = EOS;
  867.     }
  868.     return (FALSE);
  869. }
  870.  
  871.  
  872. static unsigned short crc16a[] = {
  873.                                   0000000, 0140301, 0140601, 0000500,
  874.                                   0141401, 0001700, 0001200, 0141101,
  875.                                   0143001, 0003300, 0003600, 0143501,
  876.                                   0002400, 0142701, 0142201, 0002100,
  877. };
  878.  
  879. static unsigned short crc16b[] = {
  880.                                   0000000, 0146001, 0154001, 0012000,
  881.                                   0170001, 0036000, 0024000, 0162001,
  882.                                   0120001, 0066000, 0074000, 0132001,
  883.                                   0050000, 0116001, 0104001, 0043000,
  884. };
  885.  
  886.  
  887. /*
  888.  * Return the CRC16 hash code for the buffer
  889.  * Algorithm from Stu Wecker (Digital memo 130-959-002-00).
  890.  */
  891.  
  892. unsigned short
  893. hash(buffer)
  894.     char           *buffer;
  895. {
  896.     register unsigned short crc;
  897.     register char  *tp;
  898.     register short  temp;
  899.  
  900.     crc = 0;
  901.     for (tp = buffer; *tp != EOS;) {
  902.         temp = *tp++ ^ crc;        /* XOR crc with new char  */
  903.         crc = (crc >> 8)
  904.             ^ crc16a[(temp & 0017)]
  905.             ^ crc16b[(temp & 0360) >> 4];
  906.     }
  907. #ifdef  DEBUG_ALL
  908.     printf("%06o: %s\n", (crc == 0) ? 1 : crc, buffer);
  909. #endif /* DEBUG_ALL */
  910.     return ((crc == 0) ? (unsigned short) 1 : crc);
  911. }
  912.  
  913.  
  914. #ifdef vms
  915. opendir(which, arg, okfd)
  916.     int             which;        /* Which file to open (0 or 1)       */
  917.     char          **arg;        /* File name argument, &argv[which]  */
  918.     FILE           *okfd;        /* File name (already open)       */
  919. {
  920.     register char  *tp;
  921.     register int    c;
  922.     register char  *newname;
  923.  
  924.     fgetname(okfd, text);
  925.  
  926.     /*
  927.      * Skip over device name 
  928.      */
  929.     for (tp = text; (c = *tp) && c != ':'; tp++);
  930.     if (c)
  931.         tp++;
  932.     else
  933.         tp = text;
  934.  
  935.     /*
  936.      * Skip over [UIC] or [PPN] if present 
  937.      */
  938.     if (*tp == '[' || *tp == '(') {
  939.         while ((c = *tp++) && c != ']' && c != ')');
  940.         if (c == 0) {
  941.             fprintf(stderr, "?Bug: bad file name \"%s\"\n",
  942.                     text);
  943.             tp--;
  944.         }
  945.     }
  946.     strcpy(text, tp);
  947.  
  948.     /*
  949.      * Don't include version 
  950.      */
  951.     for (tp = text; (c = *tp) && c != ';'; tp++);
  952.     *tp = 0;
  953.  
  954.     /*
  955.      * Now, text has the file name, tp - text, its length, and *arg the
  956.      * (possible) directory name.  Create a new file name for opening. 
  957.      */
  958. #ifndef    OSK
  959.     if ((newname = malloc(tp - text + strlen(*arg) + 1)) == NULL)
  960.         error("Out of space at start");
  961. #ifdef    AMIGA
  962.     savsiz = tp - text + strlen(*arg) + 1;
  963.     savptr = newname;
  964. #endif /* AMIGA */
  965. #else /* OSK */
  966.     newname = myalloc(tp - text + strlen(*arg) + 1, "Out of space at start");
  967. #endif /* OSK */
  968.     concat(newname, *arg, text, NULL);
  969.     if ((infd[which] = fopen(newname, "r")) == NULL)
  970.         cant(*arg, "constructed input", 1);
  971.     else
  972.         *arg = newname;
  973. }
  974. /* Amiga C doesn't have all these extensions for directory... */
  975. #endif /* vms */
  976.  
  977.  
  978. /*
  979.  * Allocate or crash.
  980.  */
  981.  
  982. char           *
  983. myalloc(amount, why)
  984.     unsigned        amount;
  985.     char           *why;
  986. {
  987.     register char  *pointer;
  988.  
  989. #ifdef OSK
  990.     amount += sizeof(int);
  991. #endif /* OSK */
  992.     if ((pointer = malloc((unsigned) amount)) == NULL)
  993.         noroom(why);
  994. #ifdef OSK
  995.     *((int *) pointer) = amount;
  996.     pointer += sizeof(int);
  997. #ifdef DEBUG
  998.     fprintf(stderr, "Myalloc: %d at %06o\n", amount, pointer);
  999. #endif /* DEBUG */
  1000. #endif /* OSK */
  1001. #ifdef    AMIGA
  1002.     savsiz = amount;
  1003.     savptr = pointer;
  1004. #endif /* AMIGA */
  1005.  
  1006.     return (pointer);
  1007. }
  1008.  
  1009.  
  1010. /*
  1011.  * Reallocate pointer, compacting storage
  1012.  *
  1013.  * The "compacting storage" part is probably not relevant any more.
  1014.  * There used to be horrid code here that malloc'd one byte and freed
  1015.  * it at magic times, to cause garbage collection of the freespace
  1016.  * or something.  It's safely gone now, you didn't have to see it.
  1017.  *    -- John Gilmore, Nebula Consultants, Sept 26, 1986
  1018.  */
  1019.  
  1020. char           *
  1021. compact(pointer, new_amount, why)
  1022.     char           *pointer;
  1023.     unsigned        new_amount;
  1024.     char           *why;
  1025. {
  1026.     register char  *new_pointer;
  1027.  
  1028. #ifndef AMIGA
  1029. #ifndef OSK
  1030. #ifdef TURBO
  1031.     extern void    *realloc();
  1032. #else /* !TURBO */
  1033.     extern char    *realloc();
  1034. #endif /* TURBO */
  1035.  
  1036.     if ((new_pointer = realloc(pointer, (unsigned) new_amount)) == NULL) {
  1037.         noroom(why);
  1038.     }
  1039. #else /* OSK */
  1040.     register int    old_amount;
  1041.     new_amount += sizeof(int);
  1042.     if ((new_pointer = malloc(new_amount)) == NULL)
  1043.         noroom(why);
  1044.     *(int *) new_pointer = new_amount;
  1045.     new_pointer += sizeof(int);
  1046.     old_amount = *(((int *) pointer) - 1);
  1047.     /* _strass is like bcopy with the first two arguments reversted */
  1048.     _strass(new_pointer, pointer, (new_amount <= old_amount ?
  1049.                                    new_amount : old_amount) - sizeof(int));
  1050. #ifdef DEBUG
  1051.     fprintf(stderr, "compact %d to %d from %06o to %06o\n",
  1052.             old_amount, new_amount, pointer, new_pointer);
  1053. #endif /* DEBUG */
  1054.     free(pointer - sizeof(int));
  1055. #endif /* OSK */
  1056. #else /* AMIGA */
  1057.  
  1058.     /*
  1059.      * This routine is heavily dependent on C storage allocator hacks For
  1060.      * Amiga, we can't rely on storage being left alone "up to" the boundary
  1061.      * of allocation as in VMS or RSX. Therefore we have to be different here
  1062.      * and allocate a new larger segment, then free the old one. Messy but
  1063.      * hopefully it will work. 
  1064.      */
  1065.     extern char    *malloc();
  1066.  
  1067.     /* No realloc().  Do a malloc and copy it.  */
  1068.     if ((new_pointer = malloc((unsigned) new_amount)) == NULL) {
  1069.         noroom(why);
  1070.     }
  1071.   /* This MUST assume the program calls compact using the old pointer as the
  1072.   last call of malloc... Reason is that RSX version is really simpleminded */
  1073.     cpysiz = savsiz;
  1074.   /* Complain if deallocate area not same as last allocate area */
  1075.     if (savptr != pointer)
  1076.         bogus(why);
  1077.     wrk2 = new_pointer;
  1078.     for (wrk = pointer; cpysiz > 0; cpysiz--) {
  1079.   /* copy data to new area */
  1080.         *wrk2++ = *wrk++;
  1081.     }
  1082.   /* when done, free old memory area. */
  1083.     free(pointer);
  1084. #endif /* AMIGA */
  1085.  
  1086. #ifndef OSK
  1087. #ifdef  DEBUG
  1088.     if (new_pointer != pointer) {
  1089.         fprintf(stderr, "moved from %06o to %06o\n",
  1090.                 pointer, new_pointer);
  1091.     }
  1092. /*  rdump(new_pointer, why);
  1093. */
  1094. #endif /* DEBUG */
  1095. #endif /* OSK */
  1096.     return (new_pointer);
  1097. }
  1098.  
  1099.  
  1100. noroom(why)
  1101.     char           *why;
  1102. {
  1103.     fprintf(stderr, "?DIFF-F-out of room when %s\n", why);
  1104.     exit(IO_ERROR);
  1105. }
  1106.  
  1107.  
  1108. #ifdef    AMIGA
  1109. bogus(why)
  1110.     char           *why;
  1111. {
  1112.     fprintf(stderr, "?DIFF-F-invalid compaction when %s\n", why);
  1113.     exit(IO_ERROR);
  1114. }
  1115. #endif    /* AMIGA */
  1116.  
  1117.  
  1118. #ifdef  DEBUG
  1119. /*
  1120.  * Dump memory block
  1121.  */
  1122.  
  1123. rdump(pointer, why)
  1124.     int            *pointer;
  1125.     char           *why;
  1126. {
  1127.     int            *last;
  1128.     int             count;
  1129.  
  1130.     last = ((int **) pointer)[-1];
  1131.     fprintf(stderr, "dump %s of %06o -> %06o, %d words",
  1132.             why, pointer, last, last - pointer);
  1133.     last = (int *) (((int) last) & ~1);
  1134.     for (count = 0; pointer < last; ++count) {
  1135.         if ((count & 07) == 0) {
  1136.             fprintf(stderr, "\n%06o", pointer);
  1137.         }
  1138.         fprintf(stderr, "\t%06o", *pointer);
  1139.         pointer++;
  1140.     }
  1141.     fprintf(stderr, "\n");
  1142. }
  1143. #endif /* DEBUG */
  1144.  
  1145.  
  1146. /*
  1147.  * Can't open file message
  1148.  */
  1149.  
  1150. cant(filename, what, fatalflag)
  1151.     char           *filename;
  1152.     char           *what;
  1153.     int             fatalflag;
  1154. {
  1155.     fprintf(stderr, "Can't open %s file \"%s\": ", what, filename);
  1156. #ifndef    OSK
  1157.     perror((char *) NULL);
  1158. #else
  1159.     prerr(0, errno);
  1160. #endif
  1161.     if (fatalflag) {
  1162.         exit(fatalflag);
  1163.     }
  1164. }
  1165.  
  1166.  
  1167. #ifdef  DEBUG
  1168. dump(d_linep, d_len, d_which)
  1169.     LINE           *d_linep;
  1170.     int                d_len;
  1171.     int                d_which;
  1172. {
  1173.     register int    i;
  1174.  
  1175.     printf("Dump of file%c, %d elements\n", "AB"[d_which], d_len);
  1176.     printf("linep @ %06o\n", d_linep);
  1177.     for (i = 0; i <= d_len; i++) {
  1178.         printf("%3d  %6d  %06o\n", i,
  1179.                d_linep[i].serial, d_linep[i].hash);
  1180.     }
  1181. }
  1182.  
  1183.  
  1184. /*
  1185.  * Dump klist
  1186.  */
  1187.  
  1188. dumpklist(kmax, why)
  1189.     int             kmax;
  1190.     char           *why;
  1191. {
  1192.     register int    i;
  1193.     register CANDIDATE *cp;
  1194.     register int    count;
  1195.  
  1196.     printf("\nklist[0..%d] %s, clength = %d\n", kmax, why, clength);
  1197.     for (i = 0; i <= kmax; i++) {
  1198.         cp = &clist[klist[i]];
  1199.         printf("%2d %2d", i, klist[i]);
  1200.         if (cp >= &clist[0] && cp < &clist[clength])
  1201.             printf(" (%2d %2d -> %2d)\n", cp->a, cp->b, cp->link);
  1202.         else if (klist[i] == -1)
  1203.             printf(" End of chain\n");
  1204.         else
  1205.             printf(" illegal klist element\n");
  1206.     }
  1207.     for (i = 0; i <= kmax; i++) {
  1208.         count = -1;
  1209.         for (cp = (CANDIDATE *) klist[i]; cp > &clist[0];
  1210.              cp = (CANDIDATE *) & cp->link) {
  1211.             if (++count >= 6) {
  1212.                 printf("\n    ");
  1213.                 count = 0;
  1214.             }
  1215.             printf(" (%2d: %2d,%2d -> %d)",
  1216.                    cp - clist, cp->a, cp->b, cp->link);
  1217.         }
  1218.         printf("\n");
  1219.     }
  1220.     printf("*\n");
  1221. }
  1222. #endif    /* DEBUG */
  1223.  
  1224.  
  1225.  
  1226. #ifdef  TIMING
  1227.  
  1228. /*
  1229.  * Dump time buffer
  1230.  */
  1231.  
  1232. ptime(why)
  1233.     char           *why;
  1234. {
  1235.     long            ttemp;
  1236.  
  1237.     ttemp = time(NULL);
  1238.     printf("%ld seconds for %s\n",
  1239.            ttemp - sectiontime, why);
  1240.     sectiontime = ttemp;
  1241. }
  1242. #endif    /* TIMING */
  1243.  
  1244.  
  1245. /*
  1246.  * TRUE if strings are identical
  1247.  */
  1248.  
  1249. int
  1250. streq(s1, s2)
  1251.     register char  *s1;
  1252.     register char  *s2;
  1253. {
  1254.     while (*s1++ == *s2) {
  1255.         if (*s2++ == EOS)
  1256.             return (TRUE);
  1257.     }
  1258.     return (FALSE);
  1259. }
  1260.  
  1261.  
  1262. /*
  1263.  * Error message before retiring.
  1264.  */
  1265.  
  1266. /* VARARGS */
  1267. error(format, args)
  1268.     char           *format;
  1269. {
  1270.     fprintf(stderr, format, &args);
  1271.     putc('\n', stderr);
  1272.     _error();
  1273. }
  1274.  
  1275.  
  1276. _error()
  1277. {
  1278.     exit(1);
  1279. }
  1280.  
  1281.  
  1282. /*
  1283.  * Like fput() except that it puts a newline at the end of the line.
  1284.  */
  1285.  
  1286. fputss(s, iop)
  1287.     register char  *s;
  1288.     register FILE  *iop;
  1289. {
  1290.     fputs(s, iop);
  1291.     putc('\n', iop);
  1292. }
  1293.  
  1294.  
  1295. /*
  1296.  * Fgetss() is like fgets() except that the terminating newline
  1297.  * is removed. 
  1298.  */
  1299.  
  1300. char           *
  1301. fgetss(s, n, iop)
  1302.     char           *s;
  1303.     register FILE  *iop;
  1304. {
  1305.     register char  *cs;
  1306.  
  1307.     if (fgets(s, n, iop) == NULL)
  1308.         return ((char *) NULL);
  1309.     cs = s + strlen(s) - 1;
  1310.     if (*cs == '\n')
  1311.         *cs = '\0';
  1312.     return (s);
  1313. }
  1314.