xref: /freebsd-src/contrib/diff/src/io.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
1*18fd37a7SXin LI /* File I/O for GNU DIFF.
2*18fd37a7SXin LI 
3*18fd37a7SXin LI    Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1998, 2001, 2002,
4*18fd37a7SXin LI    2004 Free Software Foundation, Inc.
5*18fd37a7SXin LI 
6*18fd37a7SXin LI    This file is part of GNU DIFF.
7*18fd37a7SXin LI 
8*18fd37a7SXin LI    GNU DIFF is free software; you can redistribute it and/or modify
9*18fd37a7SXin LI    it under the terms of the GNU General Public License as published by
10*18fd37a7SXin LI    the Free Software Foundation; either version 2, or (at your option)
11*18fd37a7SXin LI    any later version.
12*18fd37a7SXin LI 
13*18fd37a7SXin LI    GNU DIFF is distributed in the hope that it will be useful,
14*18fd37a7SXin LI    but WITHOUT ANY WARRANTY; without even the implied warranty of
15*18fd37a7SXin LI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*18fd37a7SXin LI    GNU General Public License for more details.
17*18fd37a7SXin LI 
18*18fd37a7SXin LI    You should have received a copy of the GNU General Public License
19*18fd37a7SXin LI    along with this program; see the file COPYING.
20*18fd37a7SXin LI    If not, write to the Free Software Foundation,
21*18fd37a7SXin LI    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
22*18fd37a7SXin LI 
23*18fd37a7SXin LI #include "diff.h"
24*18fd37a7SXin LI #include <cmpbuf.h>
25*18fd37a7SXin LI #include <file-type.h>
26*18fd37a7SXin LI #include <setmode.h>
27*18fd37a7SXin LI #include <xalloc.h>
28*18fd37a7SXin LI 
29*18fd37a7SXin LI /* Rotate an unsigned value to the left.  */
30*18fd37a7SXin LI #define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n)))
31*18fd37a7SXin LI 
32*18fd37a7SXin LI /* Given a hash value and a new character, return a new hash value.  */
33*18fd37a7SXin LI #define HASH(h, c) ((c) + ROL (h, 7))
34*18fd37a7SXin LI 
35*18fd37a7SXin LI /* The type of a hash value.  */
36*18fd37a7SXin LI typedef size_t hash_value;
37*18fd37a7SXin LI verify (hash_value_is_unsigned, ! TYPE_SIGNED (hash_value));
38*18fd37a7SXin LI 
39*18fd37a7SXin LI /* Lines are put into equivalence classes of lines that match in lines_differ.
40*18fd37a7SXin LI    Each equivalence class is represented by one of these structures,
41*18fd37a7SXin LI    but only while the classes are being computed.
42*18fd37a7SXin LI    Afterward, each class is represented by a number.  */
43*18fd37a7SXin LI struct equivclass
44*18fd37a7SXin LI {
45*18fd37a7SXin LI   lin next;		/* Next item in this bucket.  */
46*18fd37a7SXin LI   hash_value hash;	/* Hash of lines in this class.  */
47*18fd37a7SXin LI   char const *line;	/* A line that fits this class.  */
48*18fd37a7SXin LI   size_t length;	/* That line's length, not counting its newline.  */
49*18fd37a7SXin LI };
50*18fd37a7SXin LI 
51*18fd37a7SXin LI /* Hash-table: array of buckets, each being a chain of equivalence classes.
52*18fd37a7SXin LI    buckets[-1] is reserved for incomplete lines.  */
53*18fd37a7SXin LI static lin *buckets;
54*18fd37a7SXin LI 
55*18fd37a7SXin LI /* Number of buckets in the hash table array, not counting buckets[-1].  */
56*18fd37a7SXin LI static size_t nbuckets;
57*18fd37a7SXin LI 
58*18fd37a7SXin LI /* Array in which the equivalence classes are allocated.
59*18fd37a7SXin LI    The bucket-chains go through the elements in this array.
60*18fd37a7SXin LI    The number of an equivalence class is its index in this array.  */
61*18fd37a7SXin LI static struct equivclass *equivs;
62*18fd37a7SXin LI 
63*18fd37a7SXin LI /* Index of first free element in the array `equivs'.  */
64*18fd37a7SXin LI static lin equivs_index;
65*18fd37a7SXin LI 
66*18fd37a7SXin LI /* Number of elements allocated in the array `equivs'.  */
67*18fd37a7SXin LI static lin equivs_alloc;
68*18fd37a7SXin LI 
69*18fd37a7SXin LI /* Read a block of data into a file buffer, checking for EOF and error.  */
70*18fd37a7SXin LI 
71*18fd37a7SXin LI void
file_block_read(struct file_data * current,size_t size)72*18fd37a7SXin LI file_block_read (struct file_data *current, size_t size)
73*18fd37a7SXin LI {
74*18fd37a7SXin LI   if (size && ! current->eof)
75*18fd37a7SXin LI     {
76*18fd37a7SXin LI       size_t s = block_read (current->desc,
77*18fd37a7SXin LI 			     FILE_BUFFER (current) + current->buffered, size);
78*18fd37a7SXin LI       if (s == SIZE_MAX)
79*18fd37a7SXin LI 	pfatal_with_name (current->name);
80*18fd37a7SXin LI       current->buffered += s;
81*18fd37a7SXin LI       current->eof = s < size;
82*18fd37a7SXin LI     }
83*18fd37a7SXin LI }
84*18fd37a7SXin LI 
85*18fd37a7SXin LI /* Check for binary files and compare them for exact identity.  */
86*18fd37a7SXin LI 
87*18fd37a7SXin LI /* Return 1 if BUF contains a non text character.
88*18fd37a7SXin LI    SIZE is the number of characters in BUF.  */
89*18fd37a7SXin LI 
90*18fd37a7SXin LI #define binary_file_p(buf, size) (memchr (buf, 0, size) != 0)
91*18fd37a7SXin LI 
92*18fd37a7SXin LI /* Get ready to read the current file.
93*18fd37a7SXin LI    Return nonzero if SKIP_TEST is zero,
94*18fd37a7SXin LI    and if it appears to be a binary file.  */
95*18fd37a7SXin LI 
96*18fd37a7SXin LI static bool
sip(struct file_data * current,bool skip_test)97*18fd37a7SXin LI sip (struct file_data *current, bool skip_test)
98*18fd37a7SXin LI {
99*18fd37a7SXin LI   /* If we have a nonexistent file at this stage, treat it as empty.  */
100*18fd37a7SXin LI   if (current->desc < 0)
101*18fd37a7SXin LI     {
102*18fd37a7SXin LI       /* Leave room for a sentinel.  */
103*18fd37a7SXin LI       current->bufsize = sizeof (word);
104*18fd37a7SXin LI       current->buffer = xmalloc (current->bufsize);
105*18fd37a7SXin LI     }
106*18fd37a7SXin LI   else
107*18fd37a7SXin LI     {
108*18fd37a7SXin LI       current->bufsize = buffer_lcm (sizeof (word),
109*18fd37a7SXin LI 				     STAT_BLOCKSIZE (current->stat),
110*18fd37a7SXin LI 				     PTRDIFF_MAX - 2 * sizeof (word));
111*18fd37a7SXin LI       current->buffer = xmalloc (current->bufsize);
112*18fd37a7SXin LI 
113*18fd37a7SXin LI       if (! skip_test)
114*18fd37a7SXin LI 	{
115*18fd37a7SXin LI 	  /* Check first part of file to see if it's a binary file.  */
116*18fd37a7SXin LI 
117*18fd37a7SXin LI 	  bool was_binary = set_binary_mode (current->desc, true);
118*18fd37a7SXin LI 	  off_t buffered;
119*18fd37a7SXin LI 	  file_block_read (current, current->bufsize);
120*18fd37a7SXin LI 	  buffered = current->buffered;
121*18fd37a7SXin LI 
122*18fd37a7SXin LI 	  if (! was_binary)
123*18fd37a7SXin LI 	    {
124*18fd37a7SXin LI 	      /* Revert to text mode and seek back to the beginning to
125*18fd37a7SXin LI 		 reread the file.  Use relative seek, since file
126*18fd37a7SXin LI 		 descriptors like stdin might not start at offset
127*18fd37a7SXin LI 		 zero.  */
128*18fd37a7SXin LI 
129*18fd37a7SXin LI 	      if (lseek (current->desc, - buffered, SEEK_CUR) == -1)
130*18fd37a7SXin LI 		pfatal_with_name (current->name);
131*18fd37a7SXin LI 	      set_binary_mode (current->desc, false);
132*18fd37a7SXin LI 	      current->buffered = 0;
133*18fd37a7SXin LI 	      current->eof = false;
134*18fd37a7SXin LI 	    }
135*18fd37a7SXin LI 
136*18fd37a7SXin LI 	  return binary_file_p (current->buffer, buffered);
137*18fd37a7SXin LI 	}
138*18fd37a7SXin LI     }
139*18fd37a7SXin LI 
140*18fd37a7SXin LI   current->buffered = 0;
141*18fd37a7SXin LI   current->eof = false;
142*18fd37a7SXin LI   return false;
143*18fd37a7SXin LI }
144*18fd37a7SXin LI 
145*18fd37a7SXin LI /* Slurp the rest of the current file completely into memory.  */
146*18fd37a7SXin LI 
147*18fd37a7SXin LI static void
slurp(struct file_data * current)148*18fd37a7SXin LI slurp (struct file_data *current)
149*18fd37a7SXin LI {
150*18fd37a7SXin LI   size_t cc;
151*18fd37a7SXin LI 
152*18fd37a7SXin LI   if (current->desc < 0)
153*18fd37a7SXin LI     {
154*18fd37a7SXin LI       /* The file is nonexistent.  */
155*18fd37a7SXin LI       return;
156*18fd37a7SXin LI     }
157*18fd37a7SXin LI 
158*18fd37a7SXin LI   if (S_ISREG (current->stat.st_mode))
159*18fd37a7SXin LI     {
160*18fd37a7SXin LI       /* It's a regular file; slurp in the rest all at once.  */
161*18fd37a7SXin LI 
162*18fd37a7SXin LI       /* Get the size out of the stat block.
163*18fd37a7SXin LI 	 Allocate just enough room for appended newline plus word sentinel,
164*18fd37a7SXin LI 	 plus word-alignment since we want the buffer word-aligned.  */
165*18fd37a7SXin LI       size_t file_size = current->stat.st_size;
166*18fd37a7SXin LI       cc = file_size + 2 * sizeof (word) - file_size % sizeof (word);
167*18fd37a7SXin LI       if (file_size != current->stat.st_size || cc < file_size
168*18fd37a7SXin LI 	  || PTRDIFF_MAX <= cc)
169*18fd37a7SXin LI 	xalloc_die ();
170*18fd37a7SXin LI 
171*18fd37a7SXin LI       if (current->bufsize < cc)
172*18fd37a7SXin LI 	{
173*18fd37a7SXin LI 	  current->bufsize = cc;
174*18fd37a7SXin LI 	  current->buffer = xrealloc (current->buffer, cc);
175*18fd37a7SXin LI 	}
176*18fd37a7SXin LI 
177*18fd37a7SXin LI       /* Try to read at least 1 more byte than the size indicates, to
178*18fd37a7SXin LI 	 detect whether the file is growing.  This is a nicety for
179*18fd37a7SXin LI 	 users who run 'diff' on files while they are changing.  */
180*18fd37a7SXin LI 
181*18fd37a7SXin LI       if (current->buffered <= file_size)
182*18fd37a7SXin LI 	{
183*18fd37a7SXin LI 	  file_block_read (current, file_size + 1 - current->buffered);
184*18fd37a7SXin LI 	  if (current->buffered <= file_size)
185*18fd37a7SXin LI 	    return;
186*18fd37a7SXin LI 	}
187*18fd37a7SXin LI     }
188*18fd37a7SXin LI 
189*18fd37a7SXin LI   /* It's not a regular file, or it's a growing regular file; read it,
190*18fd37a7SXin LI      growing the buffer as needed.  */
191*18fd37a7SXin LI 
192*18fd37a7SXin LI   file_block_read (current, current->bufsize - current->buffered);
193*18fd37a7SXin LI 
194*18fd37a7SXin LI   if (current->buffered)
195*18fd37a7SXin LI     {
196*18fd37a7SXin LI       while (current->buffered == current->bufsize)
197*18fd37a7SXin LI 	{
198*18fd37a7SXin LI 	  if (PTRDIFF_MAX / 2 - sizeof (word) < current->bufsize)
199*18fd37a7SXin LI 	    xalloc_die ();
200*18fd37a7SXin LI 	  current->bufsize *= 2;
201*18fd37a7SXin LI 	  current->buffer = xrealloc (current->buffer, current->bufsize);
202*18fd37a7SXin LI 	  file_block_read (current, current->bufsize - current->buffered);
203*18fd37a7SXin LI 	}
204*18fd37a7SXin LI 
205*18fd37a7SXin LI       /* Allocate just enough room for appended newline plus word
206*18fd37a7SXin LI 	 sentinel, plus word-alignment.  */
207*18fd37a7SXin LI       cc = current->buffered + 2 * sizeof (word);
208*18fd37a7SXin LI       current->bufsize = cc - cc % sizeof (word);
209*18fd37a7SXin LI       current->buffer = xrealloc (current->buffer, current->bufsize);
210*18fd37a7SXin LI     }
211*18fd37a7SXin LI }
212*18fd37a7SXin LI 
213*18fd37a7SXin LI /* Split the file into lines, simultaneously computing the equivalence
214*18fd37a7SXin LI    class for each line.  */
215*18fd37a7SXin LI 
216*18fd37a7SXin LI static void
find_and_hash_each_line(struct file_data * current)217*18fd37a7SXin LI find_and_hash_each_line (struct file_data *current)
218*18fd37a7SXin LI {
219*18fd37a7SXin LI   hash_value h;
220*18fd37a7SXin LI   char const *p = current->prefix_end;
221*18fd37a7SXin LI   unsigned char c;
222*18fd37a7SXin LI   lin i, *bucket;
223*18fd37a7SXin LI   size_t length;
224*18fd37a7SXin LI 
225*18fd37a7SXin LI   /* Cache often-used quantities in local variables to help the compiler.  */
226*18fd37a7SXin LI   char const **linbuf = current->linbuf;
227*18fd37a7SXin LI   lin alloc_lines = current->alloc_lines;
228*18fd37a7SXin LI   lin line = 0;
229*18fd37a7SXin LI   lin linbuf_base = current->linbuf_base;
230*18fd37a7SXin LI   lin *cureqs = xmalloc (alloc_lines * sizeof *cureqs);
231*18fd37a7SXin LI   struct equivclass *eqs = equivs;
232*18fd37a7SXin LI   lin eqs_index = equivs_index;
233*18fd37a7SXin LI   lin eqs_alloc = equivs_alloc;
234*18fd37a7SXin LI   char const *suffix_begin = current->suffix_begin;
235*18fd37a7SXin LI   char const *bufend = FILE_BUFFER (current) + current->buffered;
236*18fd37a7SXin LI   bool diff_length_compare_anyway =
237*18fd37a7SXin LI     ignore_white_space != IGNORE_NO_WHITE_SPACE;
238*18fd37a7SXin LI   bool same_length_diff_contents_compare_anyway =
239*18fd37a7SXin LI     diff_length_compare_anyway | ignore_case;
240*18fd37a7SXin LI 
241*18fd37a7SXin LI   while (p < suffix_begin)
242*18fd37a7SXin LI     {
243*18fd37a7SXin LI       char const *ip = p;
244*18fd37a7SXin LI 
245*18fd37a7SXin LI       h = 0;
246*18fd37a7SXin LI 
247*18fd37a7SXin LI       /* Hash this line until we find a newline.  */
248*18fd37a7SXin LI       if (ignore_case)
249*18fd37a7SXin LI 	switch (ignore_white_space)
250*18fd37a7SXin LI 	  {
251*18fd37a7SXin LI 	  case IGNORE_ALL_SPACE:
252*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
253*18fd37a7SXin LI 	      if (! isspace (c))
254*18fd37a7SXin LI 		h = HASH (h, tolower (c));
255*18fd37a7SXin LI 	    break;
256*18fd37a7SXin LI 
257*18fd37a7SXin LI 	  case IGNORE_SPACE_CHANGE:
258*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
259*18fd37a7SXin LI 	      {
260*18fd37a7SXin LI 		if (isspace (c))
261*18fd37a7SXin LI 		  {
262*18fd37a7SXin LI 		    do
263*18fd37a7SXin LI 		      if ((c = *p++) == '\n')
264*18fd37a7SXin LI 			goto hashing_done;
265*18fd37a7SXin LI 		    while (isspace (c));
266*18fd37a7SXin LI 
267*18fd37a7SXin LI 		    h = HASH (h, ' ');
268*18fd37a7SXin LI 		  }
269*18fd37a7SXin LI 
270*18fd37a7SXin LI 		/* C is now the first non-space.  */
271*18fd37a7SXin LI 		h = HASH (h, tolower (c));
272*18fd37a7SXin LI 	      }
273*18fd37a7SXin LI 	    break;
274*18fd37a7SXin LI 
275*18fd37a7SXin LI 	  case IGNORE_TAB_EXPANSION:
276*18fd37a7SXin LI 	    {
277*18fd37a7SXin LI 	      size_t column = 0;
278*18fd37a7SXin LI 	      while ((c = *p++) != '\n')
279*18fd37a7SXin LI 		{
280*18fd37a7SXin LI 		  size_t repetitions = 1;
281*18fd37a7SXin LI 
282*18fd37a7SXin LI 		  switch (c)
283*18fd37a7SXin LI 		    {
284*18fd37a7SXin LI 		    case '\b':
285*18fd37a7SXin LI 		      column -= 0 < column;
286*18fd37a7SXin LI 		      break;
287*18fd37a7SXin LI 
288*18fd37a7SXin LI 		    case '\t':
289*18fd37a7SXin LI 		      c = ' ';
290*18fd37a7SXin LI 		      repetitions = tabsize - column % tabsize;
291*18fd37a7SXin LI 		      column = (column + repetitions < column
292*18fd37a7SXin LI 				? 0
293*18fd37a7SXin LI 				: column + repetitions);
294*18fd37a7SXin LI 		      break;
295*18fd37a7SXin LI 
296*18fd37a7SXin LI 		    case '\r':
297*18fd37a7SXin LI 		      column = 0;
298*18fd37a7SXin LI 		      break;
299*18fd37a7SXin LI 
300*18fd37a7SXin LI 		    default:
301*18fd37a7SXin LI 		      c = tolower (c);
302*18fd37a7SXin LI 		      column++;
303*18fd37a7SXin LI 		      break;
304*18fd37a7SXin LI 		    }
305*18fd37a7SXin LI 
306*18fd37a7SXin LI 		  do
307*18fd37a7SXin LI 		    h = HASH (h, c);
308*18fd37a7SXin LI 		  while (--repetitions != 0);
309*18fd37a7SXin LI 		}
310*18fd37a7SXin LI 	    }
311*18fd37a7SXin LI 	    break;
312*18fd37a7SXin LI 
313*18fd37a7SXin LI 	  default:
314*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
315*18fd37a7SXin LI 	      h = HASH (h, tolower (c));
316*18fd37a7SXin LI 	    break;
317*18fd37a7SXin LI 	  }
318*18fd37a7SXin LI       else
319*18fd37a7SXin LI 	switch (ignore_white_space)
320*18fd37a7SXin LI 	  {
321*18fd37a7SXin LI 	  case IGNORE_ALL_SPACE:
322*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
323*18fd37a7SXin LI 	      if (! isspace (c))
324*18fd37a7SXin LI 		h = HASH (h, c);
325*18fd37a7SXin LI 	    break;
326*18fd37a7SXin LI 
327*18fd37a7SXin LI 	  case IGNORE_SPACE_CHANGE:
328*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
329*18fd37a7SXin LI 	      {
330*18fd37a7SXin LI 		if (isspace (c))
331*18fd37a7SXin LI 		  {
332*18fd37a7SXin LI 		    do
333*18fd37a7SXin LI 		      if ((c = *p++) == '\n')
334*18fd37a7SXin LI 			goto hashing_done;
335*18fd37a7SXin LI 		    while (isspace (c));
336*18fd37a7SXin LI 
337*18fd37a7SXin LI 		    h = HASH (h, ' ');
338*18fd37a7SXin LI 		  }
339*18fd37a7SXin LI 
340*18fd37a7SXin LI 		/* C is now the first non-space.  */
341*18fd37a7SXin LI 		h = HASH (h, c);
342*18fd37a7SXin LI 	      }
343*18fd37a7SXin LI 	    break;
344*18fd37a7SXin LI 
345*18fd37a7SXin LI 	  case IGNORE_TAB_EXPANSION:
346*18fd37a7SXin LI 	    {
347*18fd37a7SXin LI 	      size_t column = 0;
348*18fd37a7SXin LI 	      while ((c = *p++) != '\n')
349*18fd37a7SXin LI 		{
350*18fd37a7SXin LI 		  size_t repetitions = 1;
351*18fd37a7SXin LI 
352*18fd37a7SXin LI 		  switch (c)
353*18fd37a7SXin LI 		    {
354*18fd37a7SXin LI 		    case '\b':
355*18fd37a7SXin LI 		      column -= 0 < column;
356*18fd37a7SXin LI 		      break;
357*18fd37a7SXin LI 
358*18fd37a7SXin LI 		    case '\t':
359*18fd37a7SXin LI 		      c = ' ';
360*18fd37a7SXin LI 		      repetitions = tabsize - column % tabsize;
361*18fd37a7SXin LI 		      column = (column + repetitions < column
362*18fd37a7SXin LI 				? 0
363*18fd37a7SXin LI 				: column + repetitions);
364*18fd37a7SXin LI 		      break;
365*18fd37a7SXin LI 
366*18fd37a7SXin LI 		    case '\r':
367*18fd37a7SXin LI 		      column = 0;
368*18fd37a7SXin LI 		      break;
369*18fd37a7SXin LI 
370*18fd37a7SXin LI 		    default:
371*18fd37a7SXin LI 		      column++;
372*18fd37a7SXin LI 		      break;
373*18fd37a7SXin LI 		    }
374*18fd37a7SXin LI 
375*18fd37a7SXin LI 		  do
376*18fd37a7SXin LI 		    h = HASH (h, c);
377*18fd37a7SXin LI 		  while (--repetitions != 0);
378*18fd37a7SXin LI 		}
379*18fd37a7SXin LI 	    }
380*18fd37a7SXin LI 	    break;
381*18fd37a7SXin LI 
382*18fd37a7SXin LI 	  default:
383*18fd37a7SXin LI 	    while ((c = *p++) != '\n')
384*18fd37a7SXin LI 	      h = HASH (h, c);
385*18fd37a7SXin LI 	    break;
386*18fd37a7SXin LI 	  }
387*18fd37a7SXin LI 
388*18fd37a7SXin LI    hashing_done:;
389*18fd37a7SXin LI 
390*18fd37a7SXin LI       bucket = &buckets[h % nbuckets];
391*18fd37a7SXin LI       length = p - ip - 1;
392*18fd37a7SXin LI 
393*18fd37a7SXin LI       if (p == bufend
394*18fd37a7SXin LI 	  && current->missing_newline
395*18fd37a7SXin LI 	  && ROBUST_OUTPUT_STYLE (output_style))
396*18fd37a7SXin LI 	{
397*18fd37a7SXin LI 	  /* This line is incomplete.  If this is significant,
398*18fd37a7SXin LI 	     put the line into buckets[-1].  */
399*18fd37a7SXin LI 	  if (ignore_white_space < IGNORE_SPACE_CHANGE)
400*18fd37a7SXin LI 	    bucket = &buckets[-1];
401*18fd37a7SXin LI 
402*18fd37a7SXin LI 	  /* Omit the inserted newline when computing linbuf later.  */
403*18fd37a7SXin LI 	  p--;
404*18fd37a7SXin LI 	  bufend = suffix_begin = p;
405*18fd37a7SXin LI 	}
406*18fd37a7SXin LI 
407*18fd37a7SXin LI       for (i = *bucket;  ;  i = eqs[i].next)
408*18fd37a7SXin LI 	if (!i)
409*18fd37a7SXin LI 	  {
410*18fd37a7SXin LI 	    /* Create a new equivalence class in this bucket.  */
411*18fd37a7SXin LI 	    i = eqs_index++;
412*18fd37a7SXin LI 	    if (i == eqs_alloc)
413*18fd37a7SXin LI 	      {
414*18fd37a7SXin LI 		if (PTRDIFF_MAX / (2 * sizeof *eqs) <= eqs_alloc)
415*18fd37a7SXin LI 		  xalloc_die ();
416*18fd37a7SXin LI 		eqs_alloc *= 2;
417*18fd37a7SXin LI 		eqs = xrealloc (eqs, eqs_alloc * sizeof *eqs);
418*18fd37a7SXin LI 	      }
419*18fd37a7SXin LI 	    eqs[i].next = *bucket;
420*18fd37a7SXin LI 	    eqs[i].hash = h;
421*18fd37a7SXin LI 	    eqs[i].line = ip;
422*18fd37a7SXin LI 	    eqs[i].length = length;
423*18fd37a7SXin LI 	    *bucket = i;
424*18fd37a7SXin LI 	    break;
425*18fd37a7SXin LI 	  }
426*18fd37a7SXin LI 	else if (eqs[i].hash == h)
427*18fd37a7SXin LI 	  {
428*18fd37a7SXin LI 	    char const *eqline = eqs[i].line;
429*18fd37a7SXin LI 
430*18fd37a7SXin LI 	    /* Reuse existing class if lines_differ reports the lines
431*18fd37a7SXin LI                equal.  */
432*18fd37a7SXin LI 	    if (eqs[i].length == length)
433*18fd37a7SXin LI 	      {
434*18fd37a7SXin LI 		/* Reuse existing equivalence class if the lines are identical.
435*18fd37a7SXin LI 		   This detects the common case of exact identity
436*18fd37a7SXin LI 		   faster than lines_differ would.  */
437*18fd37a7SXin LI 		if (memcmp (eqline, ip, length) == 0)
438*18fd37a7SXin LI 		  break;
439*18fd37a7SXin LI 		if (!same_length_diff_contents_compare_anyway)
440*18fd37a7SXin LI 		  continue;
441*18fd37a7SXin LI 	      }
442*18fd37a7SXin LI 	    else if (!diff_length_compare_anyway)
443*18fd37a7SXin LI 	      continue;
444*18fd37a7SXin LI 
445*18fd37a7SXin LI 	    if (! lines_differ (eqline, ip))
446*18fd37a7SXin LI 	      break;
447*18fd37a7SXin LI 	  }
448*18fd37a7SXin LI 
449*18fd37a7SXin LI       /* Maybe increase the size of the line table.  */
450*18fd37a7SXin LI       if (line == alloc_lines)
451*18fd37a7SXin LI 	{
452*18fd37a7SXin LI 	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
453*18fd37a7SXin LI 	  if (PTRDIFF_MAX / 3 <= alloc_lines
454*18fd37a7SXin LI 	      || PTRDIFF_MAX / sizeof *cureqs <= 2 * alloc_lines - linbuf_base
455*18fd37a7SXin LI 	      || PTRDIFF_MAX / sizeof *linbuf <= alloc_lines - linbuf_base)
456*18fd37a7SXin LI 	    xalloc_die ();
457*18fd37a7SXin LI 	  alloc_lines = 2 * alloc_lines - linbuf_base;
458*18fd37a7SXin LI 	  cureqs = xrealloc (cureqs, alloc_lines * sizeof *cureqs);
459*18fd37a7SXin LI 	  linbuf += linbuf_base;
460*18fd37a7SXin LI 	  linbuf = xrealloc (linbuf,
461*18fd37a7SXin LI 			     (alloc_lines - linbuf_base) * sizeof *linbuf);
462*18fd37a7SXin LI 	  linbuf -= linbuf_base;
463*18fd37a7SXin LI 	}
464*18fd37a7SXin LI       linbuf[line] = ip;
465*18fd37a7SXin LI       cureqs[line] = i;
466*18fd37a7SXin LI       ++line;
467*18fd37a7SXin LI     }
468*18fd37a7SXin LI 
469*18fd37a7SXin LI   current->buffered_lines = line;
470*18fd37a7SXin LI 
471*18fd37a7SXin LI   for (i = 0;  ;  i++)
472*18fd37a7SXin LI     {
473*18fd37a7SXin LI       /* Record the line start for lines in the suffix that we care about.
474*18fd37a7SXin LI 	 Record one more line start than lines,
475*18fd37a7SXin LI 	 so that we can compute the length of any buffered line.  */
476*18fd37a7SXin LI       if (line == alloc_lines)
477*18fd37a7SXin LI 	{
478*18fd37a7SXin LI 	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
479*18fd37a7SXin LI 	  if (PTRDIFF_MAX / 3 <= alloc_lines
480*18fd37a7SXin LI 	      || PTRDIFF_MAX / sizeof *cureqs <= 2 * alloc_lines - linbuf_base
481*18fd37a7SXin LI 	      || PTRDIFF_MAX / sizeof *linbuf <= alloc_lines - linbuf_base)
482*18fd37a7SXin LI 	    xalloc_die ();
483*18fd37a7SXin LI 	  alloc_lines = 2 * alloc_lines - linbuf_base;
484*18fd37a7SXin LI 	  linbuf += linbuf_base;
485*18fd37a7SXin LI 	  linbuf = xrealloc (linbuf,
486*18fd37a7SXin LI 			     (alloc_lines - linbuf_base) * sizeof *linbuf);
487*18fd37a7SXin LI 	  linbuf -= linbuf_base;
488*18fd37a7SXin LI 	}
489*18fd37a7SXin LI       linbuf[line] = p;
490*18fd37a7SXin LI 
491*18fd37a7SXin LI       if (p == bufend)
492*18fd37a7SXin LI 	break;
493*18fd37a7SXin LI 
494*18fd37a7SXin LI       if (context <= i && no_diff_means_no_output)
495*18fd37a7SXin LI 	break;
496*18fd37a7SXin LI 
497*18fd37a7SXin LI       line++;
498*18fd37a7SXin LI 
499*18fd37a7SXin LI       while (*p++ != '\n')
500*18fd37a7SXin LI 	continue;
501*18fd37a7SXin LI     }
502*18fd37a7SXin LI 
503*18fd37a7SXin LI   /* Done with cache in local variables.  */
504*18fd37a7SXin LI   current->linbuf = linbuf;
505*18fd37a7SXin LI   current->valid_lines = line;
506*18fd37a7SXin LI   current->alloc_lines = alloc_lines;
507*18fd37a7SXin LI   current->equivs = cureqs;
508*18fd37a7SXin LI   equivs = eqs;
509*18fd37a7SXin LI   equivs_alloc = eqs_alloc;
510*18fd37a7SXin LI   equivs_index = eqs_index;
511*18fd37a7SXin LI }
512*18fd37a7SXin LI 
513*18fd37a7SXin LI /* Prepare the text.  Make sure the text end is initialized.
514*18fd37a7SXin LI    Make sure text ends in a newline,
515*18fd37a7SXin LI    but remember that we had to add one.
516*18fd37a7SXin LI    Strip trailing CRs, if that was requested.  */
517*18fd37a7SXin LI 
518*18fd37a7SXin LI static void
prepare_text(struct file_data * current)519*18fd37a7SXin LI prepare_text (struct file_data *current)
520*18fd37a7SXin LI {
521*18fd37a7SXin LI   size_t buffered = current->buffered;
522*18fd37a7SXin LI   char *p = FILE_BUFFER (current);
523*18fd37a7SXin LI   char *dst;
524*18fd37a7SXin LI 
525*18fd37a7SXin LI   if (buffered == 0 || p[buffered - 1] == '\n')
526*18fd37a7SXin LI     current->missing_newline = false;
527*18fd37a7SXin LI   else
528*18fd37a7SXin LI     {
529*18fd37a7SXin LI       p[buffered++] = '\n';
530*18fd37a7SXin LI       current->missing_newline = true;
531*18fd37a7SXin LI     }
532*18fd37a7SXin LI 
533*18fd37a7SXin LI   if (!p)
534*18fd37a7SXin LI     return;
535*18fd37a7SXin LI 
536*18fd37a7SXin LI   /* Don't use uninitialized storage when planting or using sentinels.  */
537*18fd37a7SXin LI   memset (p + buffered, 0, sizeof (word));
538*18fd37a7SXin LI 
539*18fd37a7SXin LI   if (strip_trailing_cr && (dst = memchr (p, '\r', buffered)))
540*18fd37a7SXin LI     {
541*18fd37a7SXin LI       char const *src = dst;
542*18fd37a7SXin LI       char const *srclim = p + buffered;
543*18fd37a7SXin LI 
544*18fd37a7SXin LI       do
545*18fd37a7SXin LI 	dst += ! ((*dst = *src++) == '\r' && *src == '\n');
546*18fd37a7SXin LI       while (src < srclim);
547*18fd37a7SXin LI 
548*18fd37a7SXin LI       buffered -= src - dst;
549*18fd37a7SXin LI     }
550*18fd37a7SXin LI 
551*18fd37a7SXin LI   current->buffered = buffered;
552*18fd37a7SXin LI }
553*18fd37a7SXin LI 
554*18fd37a7SXin LI /* We have found N lines in a buffer of size S; guess the
555*18fd37a7SXin LI    proportionate number of lines that will be found in a buffer of
556*18fd37a7SXin LI    size T.  However, do not guess a number of lines so large that the
557*18fd37a7SXin LI    resulting line table might cause overflow in size calculations.  */
558*18fd37a7SXin LI static lin
guess_lines(lin n,size_t s,size_t t)559*18fd37a7SXin LI guess_lines (lin n, size_t s, size_t t)
560*18fd37a7SXin LI {
561*18fd37a7SXin LI   size_t guessed_bytes_per_line = n < 10 ? 32 : s / (n - 1);
562*18fd37a7SXin LI   lin guessed_lines = MAX (1, t / guessed_bytes_per_line);
563*18fd37a7SXin LI   return MIN (guessed_lines, PTRDIFF_MAX / (2 * sizeof (char *) + 1) - 5) + 5;
564*18fd37a7SXin LI }
565*18fd37a7SXin LI 
566*18fd37a7SXin LI /* Given a vector of two file_data objects, find the identical
567*18fd37a7SXin LI    prefixes and suffixes of each object.  */
568*18fd37a7SXin LI 
569*18fd37a7SXin LI static void
find_identical_ends(struct file_data filevec[])570*18fd37a7SXin LI find_identical_ends (struct file_data filevec[])
571*18fd37a7SXin LI {
572*18fd37a7SXin LI   word *w0, *w1;
573*18fd37a7SXin LI   char *p0, *p1, *buffer0, *buffer1;
574*18fd37a7SXin LI   char const *end0, *beg0;
575*18fd37a7SXin LI   char const **linbuf0, **linbuf1;
576*18fd37a7SXin LI   lin i, lines;
577*18fd37a7SXin LI   size_t n0, n1;
578*18fd37a7SXin LI   lin alloc_lines0, alloc_lines1;
579*18fd37a7SXin LI   lin buffered_prefix, prefix_count, prefix_mask;
580*18fd37a7SXin LI   lin middle_guess, suffix_guess;
581*18fd37a7SXin LI 
582*18fd37a7SXin LI   slurp (&filevec[0]);
583*18fd37a7SXin LI   prepare_text (&filevec[0]);
584*18fd37a7SXin LI   if (filevec[0].desc != filevec[1].desc)
585*18fd37a7SXin LI     {
586*18fd37a7SXin LI       slurp (&filevec[1]);
587*18fd37a7SXin LI       prepare_text (&filevec[1]);
588*18fd37a7SXin LI     }
589*18fd37a7SXin LI   else
590*18fd37a7SXin LI     {
591*18fd37a7SXin LI       filevec[1].buffer = filevec[0].buffer;
592*18fd37a7SXin LI       filevec[1].bufsize = filevec[0].bufsize;
593*18fd37a7SXin LI       filevec[1].buffered = filevec[0].buffered;
594*18fd37a7SXin LI       filevec[1].missing_newline = filevec[0].missing_newline;
595*18fd37a7SXin LI     }
596*18fd37a7SXin LI 
597*18fd37a7SXin LI   /* Find identical prefix.  */
598*18fd37a7SXin LI 
599*18fd37a7SXin LI   w0 = filevec[0].buffer;
600*18fd37a7SXin LI   w1 = filevec[1].buffer;
601*18fd37a7SXin LI   p0 = buffer0 = (char *) w0;
602*18fd37a7SXin LI   p1 = buffer1 = (char *) w1;
603*18fd37a7SXin LI   n0 = filevec[0].buffered;
604*18fd37a7SXin LI   n1 = filevec[1].buffered;
605*18fd37a7SXin LI 
606*18fd37a7SXin LI   if (p0 == p1)
607*18fd37a7SXin LI     /* The buffers are the same; sentinels won't work.  */
608*18fd37a7SXin LI     p0 = p1 += n1;
609*18fd37a7SXin LI   else
610*18fd37a7SXin LI     {
611*18fd37a7SXin LI       /* Insert end sentinels, in this case characters that are guaranteed
612*18fd37a7SXin LI 	 to make the equality test false, and thus terminate the loop.  */
613*18fd37a7SXin LI 
614*18fd37a7SXin LI       if (n0 < n1)
615*18fd37a7SXin LI 	p0[n0] = ~p1[n0];
616*18fd37a7SXin LI       else
617*18fd37a7SXin LI 	p1[n1] = ~p0[n1];
618*18fd37a7SXin LI 
619*18fd37a7SXin LI       /* Loop until first mismatch, or to the sentinel characters.  */
620*18fd37a7SXin LI 
621*18fd37a7SXin LI       /* Compare a word at a time for speed.  */
622*18fd37a7SXin LI       while (*w0 == *w1)
623*18fd37a7SXin LI 	w0++, w1++;
624*18fd37a7SXin LI 
625*18fd37a7SXin LI       /* Do the last few bytes of comparison a byte at a time.  */
626*18fd37a7SXin LI       p0 = (char *) w0;
627*18fd37a7SXin LI       p1 = (char *) w1;
628*18fd37a7SXin LI       while (*p0 == *p1)
629*18fd37a7SXin LI 	p0++, p1++;
630*18fd37a7SXin LI 
631*18fd37a7SXin LI       /* Don't mistakenly count missing newline as part of prefix.  */
632*18fd37a7SXin LI       if (ROBUST_OUTPUT_STYLE (output_style)
633*18fd37a7SXin LI 	  && ((buffer0 + n0 - filevec[0].missing_newline < p0)
634*18fd37a7SXin LI 	      !=
635*18fd37a7SXin LI 	      (buffer1 + n1 - filevec[1].missing_newline < p1)))
636*18fd37a7SXin LI 	p0--, p1--;
637*18fd37a7SXin LI     }
638*18fd37a7SXin LI 
639*18fd37a7SXin LI   /* Now P0 and P1 point at the first nonmatching characters.  */
640*18fd37a7SXin LI 
641*18fd37a7SXin LI   /* Skip back to last line-beginning in the prefix,
642*18fd37a7SXin LI      and then discard up to HORIZON_LINES lines from the prefix.  */
643*18fd37a7SXin LI   i = horizon_lines;
644*18fd37a7SXin LI   while (p0 != buffer0 && (p0[-1] != '\n' || i--))
645*18fd37a7SXin LI     p0--, p1--;
646*18fd37a7SXin LI 
647*18fd37a7SXin LI   /* Record the prefix.  */
648*18fd37a7SXin LI   filevec[0].prefix_end = p0;
649*18fd37a7SXin LI   filevec[1].prefix_end = p1;
650*18fd37a7SXin LI 
651*18fd37a7SXin LI   /* Find identical suffix.  */
652*18fd37a7SXin LI 
653*18fd37a7SXin LI   /* P0 and P1 point beyond the last chars not yet compared.  */
654*18fd37a7SXin LI   p0 = buffer0 + n0;
655*18fd37a7SXin LI   p1 = buffer1 + n1;
656*18fd37a7SXin LI 
657*18fd37a7SXin LI   if (! ROBUST_OUTPUT_STYLE (output_style)
658*18fd37a7SXin LI       || filevec[0].missing_newline == filevec[1].missing_newline)
659*18fd37a7SXin LI     {
660*18fd37a7SXin LI       end0 = p0;	/* Addr of last char in file 0.  */
661*18fd37a7SXin LI 
662*18fd37a7SXin LI       /* Get value of P0 at which we should stop scanning backward:
663*18fd37a7SXin LI 	 this is when either P0 or P1 points just past the last char
664*18fd37a7SXin LI 	 of the identical prefix.  */
665*18fd37a7SXin LI       beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
666*18fd37a7SXin LI 
667*18fd37a7SXin LI       /* Scan back until chars don't match or we reach that point.  */
668*18fd37a7SXin LI       for (; p0 != beg0; p0--, p1--)
669*18fd37a7SXin LI 	if (*p0 != *p1)
670*18fd37a7SXin LI 	  {
671*18fd37a7SXin LI 	    /* Point at the first char of the matching suffix.  */
672*18fd37a7SXin LI 	    beg0 = p0;
673*18fd37a7SXin LI 	    break;
674*18fd37a7SXin LI 	  }
675*18fd37a7SXin LI 
676*18fd37a7SXin LI       /* Are we at a line-beginning in both files?  If not, add the rest of
677*18fd37a7SXin LI 	 this line to the main body.  Discard up to HORIZON_LINES lines from
678*18fd37a7SXin LI 	 the identical suffix.  Also, discard one extra line,
679*18fd37a7SXin LI 	 because shift_boundaries may need it.  */
680*18fd37a7SXin LI       i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n')
681*18fd37a7SXin LI 			    &&
682*18fd37a7SXin LI 			    (buffer1 == p1 || p1[-1] == '\n'));
683*18fd37a7SXin LI       while (i-- && p0 != end0)
684*18fd37a7SXin LI 	while (*p0++ != '\n')
685*18fd37a7SXin LI 	  continue;
686*18fd37a7SXin LI 
687*18fd37a7SXin LI       p1 += p0 - beg0;
688*18fd37a7SXin LI     }
689*18fd37a7SXin LI 
690*18fd37a7SXin LI   /* Record the suffix.  */
691*18fd37a7SXin LI   filevec[0].suffix_begin = p0;
692*18fd37a7SXin LI   filevec[1].suffix_begin = p1;
693*18fd37a7SXin LI 
694*18fd37a7SXin LI   /* Calculate number of lines of prefix to save.
695*18fd37a7SXin LI 
696*18fd37a7SXin LI      prefix_count == 0 means save the whole prefix;
697*18fd37a7SXin LI      we need this for options like -D that output the whole file,
698*18fd37a7SXin LI      or for enormous contexts (to avoid worrying about arithmetic overflow).
699*18fd37a7SXin LI      We also need it for options like -F that output some preceding line;
700*18fd37a7SXin LI      at least we will need to find the last few lines,
701*18fd37a7SXin LI      but since we don't know how many, it's easiest to find them all.
702*18fd37a7SXin LI 
703*18fd37a7SXin LI      Otherwise, prefix_count != 0.  Save just prefix_count lines at start
704*18fd37a7SXin LI      of the line buffer; they'll be moved to the proper location later.
705*18fd37a7SXin LI      Handle 1 more line than the context says (because we count 1 too many),
706*18fd37a7SXin LI      rounded up to the next power of 2 to speed index computation.  */
707*18fd37a7SXin LI 
708*18fd37a7SXin LI   if (no_diff_means_no_output && ! function_regexp.fastmap
709*18fd37a7SXin LI       && context < LIN_MAX / 4 && context < n0)
710*18fd37a7SXin LI     {
711*18fd37a7SXin LI       middle_guess = guess_lines (0, 0, p0 - filevec[0].prefix_end);
712*18fd37a7SXin LI       suffix_guess = guess_lines (0, 0, buffer0 + n0 - p0);
713*18fd37a7SXin LI       for (prefix_count = 1;  prefix_count <= context;  prefix_count *= 2)
714*18fd37a7SXin LI 	continue;
715*18fd37a7SXin LI       alloc_lines0 = (prefix_count + middle_guess
716*18fd37a7SXin LI 		      + MIN (context, suffix_guess));
717*18fd37a7SXin LI     }
718*18fd37a7SXin LI   else
719*18fd37a7SXin LI     {
720*18fd37a7SXin LI       prefix_count = 0;
721*18fd37a7SXin LI       alloc_lines0 = guess_lines (0, 0, n0);
722*18fd37a7SXin LI     }
723*18fd37a7SXin LI 
724*18fd37a7SXin LI   prefix_mask = prefix_count - 1;
725*18fd37a7SXin LI   lines = 0;
726*18fd37a7SXin LI   linbuf0 = xmalloc (alloc_lines0 * sizeof *linbuf0);
727*18fd37a7SXin LI   p0 = buffer0;
728*18fd37a7SXin LI 
729*18fd37a7SXin LI   /* If the prefix is needed, find the prefix lines.  */
730*18fd37a7SXin LI   if (! (no_diff_means_no_output
731*18fd37a7SXin LI 	 && filevec[0].prefix_end == p0
732*18fd37a7SXin LI 	 && filevec[1].prefix_end == p1))
733*18fd37a7SXin LI     {
734*18fd37a7SXin LI       end0 = filevec[0].prefix_end;
735*18fd37a7SXin LI       while (p0 != end0)
736*18fd37a7SXin LI 	{
737*18fd37a7SXin LI 	  lin l = lines++ & prefix_mask;
738*18fd37a7SXin LI 	  if (l == alloc_lines0)
739*18fd37a7SXin LI 	    {
740*18fd37a7SXin LI 	      if (PTRDIFF_MAX / (2 * sizeof *linbuf0) <= alloc_lines0)
741*18fd37a7SXin LI 		xalloc_die ();
742*18fd37a7SXin LI 	      alloc_lines0 *= 2;
743*18fd37a7SXin LI 	      linbuf0 = xrealloc (linbuf0, alloc_lines0 * sizeof *linbuf0);
744*18fd37a7SXin LI 	    }
745*18fd37a7SXin LI 	  linbuf0[l] = p0;
746*18fd37a7SXin LI 	  while (*p0++ != '\n')
747*18fd37a7SXin LI 	    continue;
748*18fd37a7SXin LI 	}
749*18fd37a7SXin LI     }
750*18fd37a7SXin LI   buffered_prefix = prefix_count && context < lines ? context : lines;
751*18fd37a7SXin LI 
752*18fd37a7SXin LI   /* Allocate line buffer 1.  */
753*18fd37a7SXin LI 
754*18fd37a7SXin LI   middle_guess = guess_lines (lines, p0 - buffer0, p1 - filevec[1].prefix_end);
755*18fd37a7SXin LI   suffix_guess = guess_lines (lines, p0 - buffer0, buffer1 + n1 - p1);
756*18fd37a7SXin LI   alloc_lines1 = buffered_prefix + middle_guess + MIN (context, suffix_guess);
757*18fd37a7SXin LI   if (alloc_lines1 < buffered_prefix
758*18fd37a7SXin LI       || PTRDIFF_MAX / sizeof *linbuf1 <= alloc_lines1)
759*18fd37a7SXin LI     xalloc_die ();
760*18fd37a7SXin LI   linbuf1 = xmalloc (alloc_lines1 * sizeof *linbuf1);
761*18fd37a7SXin LI 
762*18fd37a7SXin LI   if (buffered_prefix != lines)
763*18fd37a7SXin LI     {
764*18fd37a7SXin LI       /* Rotate prefix lines to proper location.  */
765*18fd37a7SXin LI       for (i = 0;  i < buffered_prefix;  i++)
766*18fd37a7SXin LI 	linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
767*18fd37a7SXin LI       for (i = 0;  i < buffered_prefix;  i++)
768*18fd37a7SXin LI 	linbuf0[i] = linbuf1[i];
769*18fd37a7SXin LI     }
770*18fd37a7SXin LI 
771*18fd37a7SXin LI   /* Initialize line buffer 1 from line buffer 0.  */
772*18fd37a7SXin LI   for (i = 0; i < buffered_prefix; i++)
773*18fd37a7SXin LI     linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
774*18fd37a7SXin LI 
775*18fd37a7SXin LI   /* Record the line buffer, adjusted so that
776*18fd37a7SXin LI      linbuf[0] points at the first differing line.  */
777*18fd37a7SXin LI   filevec[0].linbuf = linbuf0 + buffered_prefix;
778*18fd37a7SXin LI   filevec[1].linbuf = linbuf1 + buffered_prefix;
779*18fd37a7SXin LI   filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
780*18fd37a7SXin LI   filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
781*18fd37a7SXin LI   filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
782*18fd37a7SXin LI   filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
783*18fd37a7SXin LI }
784*18fd37a7SXin LI 
785*18fd37a7SXin LI /* If 1 < k, then (2**k - prime_offset[k]) is the largest prime less
786*18fd37a7SXin LI    than 2**k.  This table is derived from Chris K. Caldwell's list
787*18fd37a7SXin LI    <http://www.utm.edu/research/primes/lists/2small/>.  */
788*18fd37a7SXin LI 
789*18fd37a7SXin LI static unsigned char const prime_offset[] =
790*18fd37a7SXin LI {
791*18fd37a7SXin LI   0, 0, 1, 1, 3, 1, 3, 1, 5, 3, 3, 9, 3, 1, 3, 19, 15, 1, 5, 1, 3, 9, 3,
792*18fd37a7SXin LI   15, 3, 39, 5, 39, 57, 3, 35, 1, 5, 9, 41, 31, 5, 25, 45, 7, 87, 21,
793*18fd37a7SXin LI   11, 57, 17, 55, 21, 115, 59, 81, 27, 129, 47, 111, 33, 55, 5, 13, 27,
794*18fd37a7SXin LI   55, 93, 1, 57, 25
795*18fd37a7SXin LI };
796*18fd37a7SXin LI 
797*18fd37a7SXin LI /* Verify that this host's size_t is not too wide for the above table.  */
798*18fd37a7SXin LI 
799*18fd37a7SXin LI verify (enough_prime_offsets,
800*18fd37a7SXin LI 	sizeof (size_t) * CHAR_BIT <= sizeof prime_offset);
801*18fd37a7SXin LI 
802*18fd37a7SXin LI /* Given a vector of two file_data objects, read the file associated
803*18fd37a7SXin LI    with each one, and build the table of equivalence classes.
804*18fd37a7SXin LI    Return nonzero if either file appears to be a binary file.
805*18fd37a7SXin LI    If PRETEND_BINARY is nonzero, pretend they are binary regardless.  */
806*18fd37a7SXin LI 
807*18fd37a7SXin LI bool
read_files(struct file_data filevec[],bool pretend_binary)808*18fd37a7SXin LI read_files (struct file_data filevec[], bool pretend_binary)
809*18fd37a7SXin LI {
810*18fd37a7SXin LI   int i;
811*18fd37a7SXin LI   bool skip_test = text | pretend_binary;
812*18fd37a7SXin LI   bool appears_binary = pretend_binary | sip (&filevec[0], skip_test);
813*18fd37a7SXin LI 
814*18fd37a7SXin LI   if (filevec[0].desc != filevec[1].desc)
815*18fd37a7SXin LI     appears_binary |= sip (&filevec[1], skip_test | appears_binary);
816*18fd37a7SXin LI   else
817*18fd37a7SXin LI     {
818*18fd37a7SXin LI       filevec[1].buffer = filevec[0].buffer;
819*18fd37a7SXin LI       filevec[1].bufsize = filevec[0].bufsize;
820*18fd37a7SXin LI       filevec[1].buffered = filevec[0].buffered;
821*18fd37a7SXin LI     }
822*18fd37a7SXin LI   if (appears_binary)
823*18fd37a7SXin LI     {
824*18fd37a7SXin LI       set_binary_mode (filevec[0].desc, true);
825*18fd37a7SXin LI       set_binary_mode (filevec[1].desc, true);
826*18fd37a7SXin LI       return true;
827*18fd37a7SXin LI     }
828*18fd37a7SXin LI 
829*18fd37a7SXin LI   find_identical_ends (filevec);
830*18fd37a7SXin LI 
831*18fd37a7SXin LI   equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
832*18fd37a7SXin LI   if (PTRDIFF_MAX / sizeof *equivs <= equivs_alloc)
833*18fd37a7SXin LI     xalloc_die ();
834*18fd37a7SXin LI   equivs = xmalloc (equivs_alloc * sizeof *equivs);
835*18fd37a7SXin LI   /* Equivalence class 0 is permanently safe for lines that were not
836*18fd37a7SXin LI      hashed.  Real equivalence classes start at 1.  */
837*18fd37a7SXin LI   equivs_index = 1;
838*18fd37a7SXin LI 
839*18fd37a7SXin LI   /* Allocate (one plus) a prime number of hash buckets.  Use a prime
840*18fd37a7SXin LI      number between 1/3 and 2/3 of the value of equiv_allocs,
841*18fd37a7SXin LI      approximately.  */
842*18fd37a7SXin LI   for (i = 9; (size_t) 1 << i < equivs_alloc / 3; i++)
843*18fd37a7SXin LI     continue;
844*18fd37a7SXin LI   nbuckets = ((size_t) 1 << i) - prime_offset[i];
845*18fd37a7SXin LI   if (PTRDIFF_MAX / sizeof *buckets <= nbuckets)
846*18fd37a7SXin LI     xalloc_die ();
847*18fd37a7SXin LI   buckets = zalloc ((nbuckets + 1) * sizeof *buckets);
848*18fd37a7SXin LI   buckets++;
849*18fd37a7SXin LI 
850*18fd37a7SXin LI   for (i = 0; i < 2; i++)
851*18fd37a7SXin LI     find_and_hash_each_line (&filevec[i]);
852*18fd37a7SXin LI 
853*18fd37a7SXin LI   filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
854*18fd37a7SXin LI 
855*18fd37a7SXin LI   free (equivs);
856*18fd37a7SXin LI   free (buckets - 1);
857*18fd37a7SXin LI 
858*18fd37a7SXin LI   return false;
859*18fd37a7SXin LI }
860