home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / rcs567s.zip / diff16 / io.c < prev    next >
C/C++ Source or Header  |  1994-06-25  |  23KB  |  773 lines

  1. /* File I/O for GNU DIFF.
  2.    Copyright (C) 1988, 1989 Free Software Foundation, Inc.
  3.    Modified for DOS and OS/2 on 1991/09/14 by Kai Uwe Rommel
  4.     <rommel@ars.muc.de>.
  5.  
  6. This file is part of GNU DIFF.
  7.  
  8. GNU DIFF is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 1, or (at your option)
  11. any later version.
  12.  
  13. GNU DIFF is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with GNU DIFF; see the file COPYING.  If not, write to
  20. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  21.  
  22. #include "diff.h"
  23.  
  24. /* Rotate a value n bits to the left. */
  25. #if !defined(MSDOS)
  26. #define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
  27. #define ROL(v, n) ((v) << (n) | (v) >> UINT_BIT - (n))
  28. #else
  29. #define ROL(v,n)  ((v) << (n) | (v) >> (sizeof(v) * CHAR_BIT) - (n))
  30. #endif
  31.  
  32. /* Given a hash value and a new character, return a new hash value. */
  33. #define HASH(h, c) ((c) + ROL (h, 7))
  34.  
  35. /* Current file under consideration. */
  36. struct file_data *current;
  37.  
  38. /* Check for binary files and compare them for exact identity.  */
  39.  
  40. /* Return 1 if BUF contains a non text character.
  41.    SIZE is the number of characters in BUF.  */
  42.  
  43. static int
  44. binary_file_p (buf, size)
  45.      char *buf;
  46.      int size;
  47. {
  48.   static const char textchar[] = {
  49.     /* ISO 8859 */
  50.     0, 0, 0, 0, 0, 0, 0, 0,
  51.     0, 1, 1, 1, 1, 1, 0, 0,
  52.     0, 0, 0, 0, 0, 0, 0, 0,
  53.     0, 0, 0, 0, 0, 0, 0, 0,
  54.     1, 1, 1, 1, 1, 1, 1, 1,
  55.     1, 1, 1, 1, 1, 1, 1, 1,
  56.     1, 1, 1, 1, 1, 1, 1, 1,
  57.     1, 1, 1, 1, 1, 1, 1, 1,
  58.     1, 1, 1, 1, 1, 1, 1, 1,
  59.     1, 1, 1, 1, 1, 1, 1, 1,
  60.     1, 1, 1, 1, 1, 1, 1, 1,
  61.     1, 1, 1, 1, 1, 1, 1, 1,
  62.     1, 1, 1, 1, 1, 1, 1, 1,
  63.     1, 1, 1, 1, 1, 1, 1, 1,
  64.     1, 1, 1, 1, 1, 1, 1, 1,
  65.     1, 1, 1, 1, 1, 1, 1, 0,
  66. #ifdef MSDOS
  67.     1, 1, 1, 1, 1, 1, 1, 1,
  68.     1, 1, 1, 1, 1, 1, 1, 1,
  69.     1, 1, 1, 1, 1, 1, 1, 1,
  70.     1, 1, 1, 1, 1, 1, 1, 1,
  71. #else
  72.     0, 0, 0, 0, 0, 0, 0, 0,
  73.     0, 0, 0, 0, 0, 0, 0, 0,
  74.     0, 0, 0, 0, 0, 0, 0, 0,
  75.     0, 0, 0, 0, 0, 0, 0, 0,
  76. #endif
  77.     1, 1, 1, 1, 1, 1, 1, 1,
  78.     1, 1, 1, 1, 1, 1, 1, 1,
  79.     1, 1, 1, 1, 1, 1, 1, 1,
  80.     1, 1, 1, 1, 1, 1, 1, 1,
  81.     1, 1, 1, 1, 1, 1, 1, 1,
  82.     1, 1, 1, 1, 1, 1, 1, 1,
  83.     1, 1, 1, 1, 1, 1, 1, 1,
  84.     1, 1, 1, 1, 1, 1, 1, 1,
  85.     1, 1, 1, 1, 1, 1, 1, 1,
  86.     1, 1, 1, 1, 1, 1, 1, 1,
  87.     1, 1, 1, 1, 1, 1, 1, 1,
  88.     1, 1, 1, 1, 1, 1, 1, 1,
  89.   };
  90.   while (--size >= 0)
  91.     if (!textchar[*buf++ & 0377])
  92.       return 1;
  93.   return 0;
  94. }
  95.  
  96. int binary_file_threshold = 512;
  97.  
  98. /* Slurp the current file completely into core.
  99.    Return nonzero if it appears to be a binary file.  */
  100.  
  101. static int
  102. slurp ()
  103. {
  104.   /* If we have a nonexistent file at this stage, treat it as empty.  */
  105.   if (current->desc < 0)
  106.     {
  107.       current->bufsize = 0;
  108.       current->buffered_chars = 0;
  109.       current->buffer = 0;
  110.     }
  111.   /* If it's a regular file, we can just get the size out of the stat
  112.      block and slurp it in all at once. */
  113.   /* In all cases, we leave room in the buffer for 2 extra chars
  114.      beyond those that current->bufsize describes:
  115.      one for a newline (in case the text does not end with one)
  116.      and one for a sentinel in find_identical_ends.  */
  117. #if !defined(MSDOS)
  118.   else if ((current->stat.st_mode & S_IFMT) == S_IFREG)
  119.     {
  120.       current->bufsize = current->stat.st_size;
  121.       current->buffer = (char *) xmalloc (current->bufsize + 2);
  122.       current->buffered_chars
  123.     = read (current->desc, current->buffer, current->bufsize);
  124.       if (current->buffered_chars < 0)
  125.     pfatal_with_name (current->name);
  126.     }
  127.   else
  128.     {
  129.       int cc;
  130.  
  131.       current->bufsize = 4096;
  132.       current->buffer = (char *) xmalloc (current->bufsize + 2);
  133.       current->buffered_chars = 0;
  134.       
  135.       /* Not a regular file; read it in a little at a time, growing the
  136.      buffer as necessary. */
  137.       while ((cc = read (current->desc,
  138.              current->buffer + current->buffered_chars,
  139.              current->bufsize - current->buffered_chars))
  140.          > 0)
  141.     {
  142.       current->buffered_chars += cc;
  143.       if (current->buffered_chars == current->bufsize)
  144.         {
  145.           current->bufsize = current->bufsize * 2;
  146.           current->buffer = (char *) xrealloc (current->buffer,
  147.                            current->bufsize + 2);
  148.         }
  149.     }
  150.       if (cc < 0)
  151.     pfatal_with_name (current->name);
  152.     }
  153. #else /* MSDOS */
  154.   else {
  155.       int count;
  156.       char huge *ptr;
  157.       char *buf;
  158. #ifdef __TURBOC__
  159.       int cnt;
  160. #endif
  161.  
  162.       current->bufsize = current->stat.st_size + 1;
  163.       if((current->buffer = halloc(current->bufsize + 2,sizeof(char))) == NULL)
  164.              fatal("virtual memory exhausted");
  165.  
  166.       current->buffered_chars = 0;
  167.       ptr = current->buffer;
  168.  
  169.      /* this kludge is the only way to prevent read() from segment
  170.       * wraparounds in real mode in a OS/2 family mode application  :-( :-(
  171.       */
  172.  
  173.       if((buf = malloc(16384)) == NULL)
  174.              fatal("virtual memory exhausted");
  175.  
  176.       while((count = read(current->desc, buf, 16384)) > 0)
  177.       {
  178. #ifdef __TURBOC__
  179.              for ( cnt = 0; cnt < count; cnt++ )
  180.                 ptr[cnt] = buf[cnt];
  181. #else
  182.              memcpy(ptr, buf, count); /* MS C memcpy is aware of huge pointers */
  183. #endif
  184.              current->buffered_chars += count;
  185.              ptr += count;
  186.       }
  187.  
  188.       free(buf);
  189.  
  190.       if (count < 0)
  191.     pfatal_with_name (current->name);
  192.     }
  193. #endif        /* MSDOS */
  194.   
  195.   /* Check first part of file to see if it's a binary file.  */
  196.   if (! always_text_flag
  197.       && binary_file_p (current->buffer,
  198.             (int) min (current->buffered_chars, binary_file_threshold)))
  199.     return 1;
  200.  
  201.   /* If not binary, make sure text ends in a newline,
  202.      but remember that we had to add one unless -B is in effect.  */
  203.   if (current->buffered_chars > 0
  204.       && current->buffer[current->buffered_chars - 1] != '\n')
  205.     {
  206.       current->missing_newline = !ignore_blank_lines_flag;
  207.       current->buffer[current->buffered_chars++] = '\n';
  208.     }
  209.   else
  210.     current->missing_newline = 0;
  211.  
  212.   /* Don't use uninitialized storage. */
  213.   if (current->buffer != 0)
  214.     current->buffer[current->buffered_chars] = '\0';
  215.  
  216.   return 0;
  217. }
  218.  
  219. /* Split the file into lines, simultaneously computing the hash codes for
  220.    each line. */
  221.  
  222. void
  223. find_and_hash_each_line ()
  224. {
  225.   unsigned h;
  226.   int i;
  227. #if !defined(MSDOS)
  228.   char *p = current->prefix_end, *ip, c;
  229. #else
  230.   char huge *p = (char huge *) current->prefix_end;
  231.   char huge *ip, c;
  232.   int old;
  233. #endif
  234.  
  235.   /* Attempt to get a good initial guess as to the number of lines. */
  236.   current->linbufsize = current->buffered_chars / 50 + 5;
  237. #if !defined(MSDOS)
  238.   current->linbuf
  239.     = (struct line_def *) xmalloc (current->linbufsize * sizeof (struct line_def));
  240. #else
  241.   current->linbuf
  242.     = halloc(current->linbufsize, sizeof(struct line_def));
  243.   if ( current->linbuf == NULL )
  244.     fatal("virtual memory exhausted");
  245. #endif
  246.  
  247.   if (function_regexp || output_style == OUTPUT_IFDEF)
  248.     {
  249.       /* If the -C, -D or -F option is used, we need to find the lines
  250.      of the matching prefix.  At least we will need to find the last few,
  251.      but since we don't know how many, it's easiest to find them all.
  252.      If -D is specified, we need all the lines of the first file.  */
  253.       current->buffered_lines = 0;
  254.       p = current->buffer;
  255.     }
  256.   else
  257.     {
  258.       /* Skip the identical prefixes, except be prepared to handle context.
  259.      In fact, handle 1 more preceding line than the context says,
  260.      in case shift_boundaries moves things backwards in this file.  */
  261.       current->buffered_lines = current->prefix_lines - context - 1;
  262.       if (current->buffered_lines < 0)
  263.     current->buffered_lines = 0;
  264.       for (i = 0; i < context + 1; ++i)
  265.     /* Unless we are at the beginning, */
  266.     if (p != current->buffer)
  267.       /* Back up at least 1 char until at the start of a line.  */
  268.       while ( --p != current->buffer && p[-1] != '\n')
  269.         ;
  270.     }
  271.  
  272.   while (p < current->suffix_begin)
  273.     {
  274.       h = 0;
  275.       ip = p;
  276.  
  277.       if (current->prefix_end <= p)
  278.     {
  279.       /* Hash this line until we find a newline. */
  280.       if (ignore_case_flag)
  281.         {
  282.           if (ignore_all_space_flag)
  283.         while ((c = *p) != '\n')
  284.           {
  285.             if (! isspace (c))
  286.               if (isupper (c))
  287.             h = HASH (h, tolower (c));
  288.               else
  289.             h = HASH (h, c);
  290.             ++p;
  291.           }
  292.           else if (ignore_space_change_flag)
  293.  
  294.         while ((c = *p) != '\n')
  295.           {
  296.             if (c == ' ' || c == '\t')
  297.               {
  298.             while ((c = *p) == ' ' || c == '\t')
  299.               ++p;
  300.             if (c == '\n')
  301.               break;
  302.             h = HASH (h, ' ');
  303.               }
  304.             /* C is now the first non-space.  */
  305.             if (isupper (c))
  306.               h = HASH (h, tolower (c));
  307.             else
  308.               h = HASH (h, c);
  309.             ++p;
  310.           }
  311.           else
  312.         while ((c = *p) != '\n')
  313.           {
  314.             if (isupper (c))
  315.               h = HASH (h, tolower (c));
  316.             else
  317.               h = HASH (h, c);
  318.             ++p;
  319.           }
  320.         }
  321.       else
  322.         {
  323.           if (ignore_all_space_flag)
  324.         while ((c = *p) != '\n')
  325.           {
  326.             if (! isspace (c))
  327.               h = HASH (h, c);
  328.             ++p;
  329.           }
  330.           else if (ignore_space_change_flag)
  331.         while ((c = *p) != '\n')
  332.           {
  333.             if (c == ' ' || c == '\t')
  334.               {
  335.             while ((c = *p) == ' ' || c == '\t')
  336.               ++p;
  337.             if (c == '\n')
  338.               break;
  339.             h = HASH (h, ' ');
  340.               }
  341.             /* C is not the first non-space.  */
  342.             h = HASH (h, c);
  343.             ++p;
  344.           }
  345.           else
  346.         while ((c = *p) != '\n')
  347.           {
  348.             h = HASH (h, c);
  349.             ++p;
  350.           }
  351.         }
  352.     }
  353.       else
  354.     /* This line is part of the matching prefix,
  355.        so we don't need to hash it.  */
  356.     while (*p != '\n')
  357.       ++p;
  358.       
  359.       /* Maybe increase the size of the line table. */
  360.       if (current->buffered_lines >= current->linbufsize)
  361.     {
  362. #ifndef MSDOS
  363.       while (current->buffered_lines >= current->linbufsize)
  364.         current->linbufsize *= 2;
  365.  
  366.       current->linbuf
  367.         = (struct line_def *) xrealloc (current->linbuf,
  368.                         current->linbufsize
  369.                         * sizeof (struct line_def));
  370. #else
  371.           old = current->linbufsize;
  372.  
  373.       while (current->buffered_lines >= current->linbufsize)
  374.         current->linbufsize += 2048;
  375.  
  376.       current->linbuf = hrealloc(current->linbuf,
  377.             (long) current->linbufsize * sizeof (struct line_def),
  378.             (long) old * sizeof (struct line_def));
  379.  
  380.           if ( current->linbuf == NULL )
  381.              fatal("too many lines");
  382. #endif
  383.     }
  384.       current->linbuf[current->buffered_lines].text = ip;
  385.       current->linbuf[current->buffered_lines].length = p - ip + 1;
  386.       current->linbuf[current->buffered_lines].hash = h;
  387.       ++current->buffered_lines;
  388.       ++p;
  389.     }
  390.  
  391.   i = 0;
  392.   while ((i < context || output_style == OUTPUT_IFDEF)
  393. #ifndef MSDOS
  394.      && (char *) p < current->buffer + current->buffered_chars)
  395. #else
  396.      && p < (char huge *) current->buffer + current->buffered_chars)
  397. #endif
  398.     {
  399.       ip = p;
  400.       while (*p++ != '\n')
  401.     ;
  402.       /* Maybe increase the size of the line table. */
  403.       if (current->buffered_lines >= current->linbufsize)
  404.     {
  405. #ifndef MSDOS
  406.       while (current->buffered_lines >= current->linbufsize)
  407.         current->linbufsize *= 2;
  408.  
  409.       current->linbuf
  410.         = (struct line_def *) xrealloc (current->linbuf,
  411.                         current->linbufsize
  412.                         * sizeof (struct line_def));
  413. #else
  414.           old = current->linbufsize;
  415.  
  416.       while (current->buffered_lines >= current->linbufsize)
  417.         current->linbufsize += 2048;
  418.  
  419.       current->linbuf = hrealloc(current->linbuf,
  420.             (long) current->linbufsize * sizeof (struct line_def),
  421.             (long) old * sizeof (struct line_def));
  422.  
  423.           if ( current->linbuf == NULL )
  424.              fatal("too many lines");
  425. #endif
  426.     }
  427.       current->linbuf[current->buffered_lines].text = ip;
  428.       current->linbuf[current->buffered_lines].length = p - ip;
  429.       current->linbuf[current->buffered_lines].hash = 0;
  430.       ++current->buffered_lines;
  431.       ++i;
  432.     }
  433.  
  434.   if (ROBUST_OUTPUT_STYLE (output_style)
  435.       && current->missing_newline
  436.       && current->suffix_begin == current->buffer + current->buffered_chars)
  437.     --current->linbuf[current->buffered_lines - 1].length;
  438. }
  439.  
  440. /* Given a vector of two file_data objects, find the identical
  441.    prefixes and suffixes of each object. */
  442.  
  443. static void
  444. find_identical_ends (filevec)
  445.      struct file_data filevec[];
  446. {
  447. #ifndef MSDOS
  448.   char *p0, *p1, *end0, *beg0;
  449. #else
  450.   char huge *p0, huge *p1, huge *end0, huge *beg0;
  451. #endif
  452.   int lines;
  453.  
  454.   if (filevec[0].buffered_chars == 0 || filevec[1].buffered_chars == 0)
  455.     {
  456.       filevec[0].prefix_end = filevec[0].buffer;
  457.       filevec[1].prefix_end = filevec[1].buffer;
  458.       filevec[0].prefix_lines = filevec[1].prefix_lines = 0;
  459.       filevec[0].suffix_begin = filevec[0].buffer + filevec[0].buffered_chars;
  460.       filevec[1].suffix_begin = filevec[1].buffer + filevec[1].buffered_chars;
  461.       filevec[0].suffix_lines = filevec[1].suffix_lines = 0;
  462.       return;
  463.     }
  464.  
  465.   /* Find identical prefix.  */
  466.  
  467.   p0 = filevec[0].buffer;
  468.   p1 = filevec[1].buffer;
  469.   lines = 0;
  470.  
  471.   /* Insert end "sentinels", in this case characters that are guaranteed
  472.      to make the equality test false, and thus terminate the loop.  */
  473.  
  474.   if (filevec[0].buffered_chars < filevec[1].buffered_chars)
  475.     p0[filevec[0].buffered_chars] = ~p1[filevec[0].buffered_chars];
  476.   else
  477.     p1[filevec[1].buffered_chars] = ~p0[filevec[1].buffered_chars];
  478.  
  479.   /* Loop until first mismatch, or to the sentinel characters.  */
  480.   while (1)
  481.     {
  482.       char c = *p0++;
  483.       if (c != *p1++)
  484.     break;
  485.       if (c == '\n')
  486.     ++lines;
  487.     }
  488.  
  489.   /* Don't count missing newline as part of prefix in RCS mode. */
  490.   if (ROBUST_OUTPUT_STYLE (output_style)
  491.       && ((filevec[0].missing_newline
  492.        && (p0 - filevec[0].buffer) > filevec[0].buffered_chars)
  493.       ||
  494.       (filevec[1].missing_newline
  495.        && (p1 - filevec[1].buffer) > filevec[1].buffered_chars)))
  496.     --p0, --p1, --lines;
  497.  
  498.   /* If the sentinel was passed, and lengths are equal, the
  499.      files are identical.  */
  500.   if ((p0 - filevec[0].buffer) > filevec[0].buffered_chars
  501.       && filevec[0].buffered_chars == filevec[1].buffered_chars)
  502.     {
  503.       filevec[0].prefix_end = p0 - 1;
  504.       filevec[1].prefix_end = p1 - 1;
  505.       filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
  506.       filevec[0].suffix_begin = filevec[0].buffer;
  507.       filevec[1].suffix_begin = filevec[1].buffer;
  508.       filevec[0].suffix_lines = filevec[1].suffix_lines = lines;
  509.       return;
  510.     }
  511.  
  512.   /* Point at first nonmatching characters.  */
  513.   --p0, --p1;
  514.  
  515.   /* Skip back to last line-beginning in the prefix.  */
  516.   while (p0 != filevec[0].buffer && p0[-1] != '\n')
  517.     --p0, --p1;
  518.  
  519.   /* Record the prefix.  */
  520.   filevec[0].prefix_end = p0;
  521.   filevec[1].prefix_end = p1;
  522.   filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
  523.   
  524.   /* Find identical suffix.  */
  525.  
  526.   /* P0 and P1 point beyond the last chars not yet compared.  */
  527.   p0 = filevec[0].buffer + filevec[0].buffered_chars;
  528.   p1 = filevec[1].buffer + filevec[1].buffered_chars;
  529.   lines = 0;
  530.  
  531.   if (! ROBUST_OUTPUT_STYLE (output_style)
  532.       || filevec[0].missing_newline == filevec[1].missing_newline)
  533.     {
  534.       end0 = p0;        /* Addr of last char in file 0.  */
  535.  
  536.       /* Get value of P0 at which we should stop scanning backward:
  537.      this is when either P0 or P1 points just past the last char
  538.      of the identical prefix.  */
  539.       if (filevec[0].buffered_chars < filevec[1].buffered_chars)
  540.     beg0 = filevec[0].prefix_end;
  541.       else
  542.     /* Figure out where P0 will be when P1 is at the end of the prefix.
  543.        Thus we only need to test P0.  */
  544.     beg0 = filevec[0].prefix_end
  545.         + (filevec[0].buffered_chars - filevec[1].buffered_chars);
  546.  
  547.       /* Scan back until chars don't match or we reach that point.  */
  548.       while (p0 > beg0)
  549.     {
  550.       char c = *--p0;
  551.       if (c != *--p1)
  552.         {
  553.           /* Point at the first char of the matching suffix.  */
  554.           ++p0, ++p1;
  555.           break;
  556.         }
  557.       if (c == '\n')
  558.         ++lines;
  559.     }
  560.  
  561.       /* Are we at a line-beginning in both files?  */
  562.       if (p0 != end0
  563.       && !((p0 == filevec[0].buffer || p0[-1] == '\n')
  564.            &&
  565.            (p1 == filevec[1].buffer || p1[-1] == '\n')))
  566.     {
  567.       /* No.  We counted one line too many.  */
  568.       --lines;
  569.       /* Advance to next place that is a line-beginning in both files.  */
  570.       do
  571.         {
  572.           ++p0, ++p1;
  573.         }
  574.       while (p0 != end0 && p0[-1] != '\n');
  575.     }
  576.     }
  577.  
  578.   /* Record the suffix.  */
  579.   filevec[0].suffix_begin = p0;
  580.   filevec[1].suffix_begin = p1;
  581.   filevec[0].suffix_lines = filevec[1].suffix_lines = lines;
  582. }
  583.  
  584. /* Lines are put into equivalence classes (of lines that match in line_cmp).
  585.    Each equivalence class is represented by one of these structures,
  586.    but only while the classes are being computed.
  587.    Afterward, each class is represented by a number.  */
  588. struct equivclass
  589. {
  590.   struct equivclass *next;    /* Next item in this bucket. */
  591.   struct line_def line;    /* A line that fits this class. */
  592. #ifdef MSDOS
  593.   long dummy; /* to pad struct size to a power of two, 16 */
  594. #endif
  595. };
  596.  
  597. /* Hash-table: array of buckets, each being a chain of equivalence classes.  */
  598. static struct equivclass **buckets;
  599.   
  600. /* Size of the bucket array. */
  601. static int nbuckets;
  602.  
  603. /* Array in which the equivalence classes are allocated.
  604.    The bucket-chains go through the elements in this array.
  605.    The number of an equivalence class is its index in this array.  */
  606. static struct equivclass huge *equivs;
  607.  
  608. /* Index of first free element in the array `equivs'.  */
  609. static long equivs_index;
  610.  
  611. /* Size allocated to the array `equivs'.  */
  612. static long equivs_alloc;
  613.  
  614. /* Largest primes less than some power of two, for nbuckets.  Values range
  615.    from useful to preposterous.  If one of these numbers isn't prime
  616.    after all, don't blame it on me, blame it on primes (6) . . . */
  617. static long primes[] =
  618. {
  619.   509,
  620.   1021,
  621.   2039,
  622.   4093,
  623.   8191,
  624.   16381,
  625.   32749,
  626.   65521,
  627.   131071,
  628.   262139,
  629.   524287,
  630.   1048573,
  631.   2097143,
  632.   4194301,
  633.   8388593,
  634.   16777213,
  635.   33554393,
  636.   67108859,            /* Preposterously large . . . */
  637.   -1
  638. };
  639.  
  640. /* Index of current nbuckets in primes. */
  641. static int primes_index;
  642.  
  643. /* Find the equiv class associated with line N of the current file.  */
  644.  
  645. static int
  646. find_equiv_class (n)
  647.      int n;
  648. {
  649.   int bucket;
  650.   struct equivclass huge *b, huge *p = NULL;
  651.  
  652.   /* Equivalence class 0 is permanently allocated to lines that were
  653.      not hashed because they were parts of identical prefixes or
  654.      suffixes. */
  655.   if (n < current->prefix_lines
  656.       || current->linbuf[n].text >= current->suffix_begin)
  657.     return 0;
  658.  
  659.   /* Check through the appropriate bucket to see if there isn't already
  660.      an equivalence class for this line. */
  661.   bucket = current->linbuf[n].hash % nbuckets;
  662.   b = buckets[bucket];
  663.   while (b)
  664.     {
  665.       if (b->line.hash == current->linbuf[n].hash
  666.       && (b->line.length == current->linbuf[n].length
  667.           /* Lines of different lengths can match with certain options.  */
  668.           || length_varies)
  669.       && !line_cmp (&b->line, ¤t->linbuf[n]))
  670.     return b - equivs;
  671.       p = b, b = b->next;
  672.     }
  673.  
  674.   /* Create a new equivalence class in this bucket. */
  675.  
  676.   if (equivs_index >= equivs_alloc)
  677.     fatal ("too many differences, hash table overflow");
  678.  
  679.   p = &equivs[equivs_index++];
  680.   p->next = buckets[bucket];
  681.   buckets[bucket] = p;
  682.   p->line = current->linbuf[n];
  683.  
  684.   return equivs_index - 1;
  685. }
  686.  
  687. /* Given a vector of two file_data objects, read the file associated
  688.    with each one, and build the table of equivalence classes.
  689.    Return nonzero if either file appears to be a binary file.  */
  690.  
  691. int
  692. read_files (filevec)
  693.      struct file_data filevec[];
  694. {
  695.   int i, j;
  696.   int binary = 0;
  697.   int this_binary;
  698.  
  699.   current = &filevec[0];
  700.   binary = this_binary = slurp ();
  701.  
  702.   current = &filevec[1];
  703.   this_binary = slurp ();
  704.   if (binary || this_binary)
  705.     return 1;
  706.  
  707.   find_identical_ends (filevec);
  708.  
  709.   for (i = 0; i < 2; ++i)
  710.     {
  711.       current = &filevec[i];
  712.       find_and_hash_each_line ();
  713.     }
  714.  
  715.   /* This is guaranteed to be enough space.  */
  716.   equivs_alloc = (long) filevec[0].buffered_lines + filevec[1].buffered_lines + 1L;
  717. #ifndef MSDOS
  718.   equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
  719. #else
  720.   equivs = halloc (equivs_alloc, sizeof (struct equivclass));
  721.   if ( equivs == NULL )
  722.     fatal("virtual memory exhausted");
  723. #endif
  724.   /* Equivalence class 0 is permanently safe for lines that were not
  725.      hashed.  Real equivalence classes start at 1. */
  726.   equivs_index = 1;
  727.   
  728.   primes_index = 0;
  729.   while (primes[primes_index] < equivs_alloc / 3)
  730.     primes_index++;
  731.  
  732. #ifndef MSDOS
  733.   buckets = (struct equivclass **) xmalloc (primes[primes_index] * sizeof (struct equivclass *));
  734.   bzero (buckets, primes[primes_index] * sizeof (struct equivclass *));
  735. #else
  736.   buckets = halloc (primes[primes_index], sizeof (struct equivclass *));
  737. #ifdef __TURBOC__
  738.   /* Microsoft C's halloc already zeroes out the allocated memory.
  739.      So this bzero call is only needed for Turbo C and Borland C.
  740.      But note that the block may be bigger than 64k and that the bzero
  741.      (actually memset) will not fill out the whole block. But this
  742.      situation is not very likely to occur, because with Turbo C or
  743.      Borland C, you can only make a MS-DOS program, who's memory
  744.      is too restricted to diff such big files that this situation
  745.      may occur.
  746.   */
  747.   bzero (buckets, primes[primes_index] * sizeof (struct equivclass *));
  748. #endif
  749. #endif
  750.   nbuckets = primes[primes_index];
  751.  
  752.   for (i = 0; i < 2; ++i)
  753.     {
  754.       current = &filevec[i];
  755.       current->equivs
  756.     = (int *) xmalloc (current->buffered_lines * sizeof (int));
  757.       for (j = 0; j < current->buffered_lines; ++j)
  758.     current->equivs[j] = find_equiv_class (j);
  759.     }
  760.  
  761.   filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
  762.  
  763. #ifndef MSDOS
  764.   free (equivs);
  765.   free (buckets);
  766. #else
  767.   hfree (equivs);
  768.   hfree (buckets);
  769. #endif
  770.  
  771.   return 0;
  772. }
  773.