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