Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/ape/cmd/diff/io.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* File I/O for GNU DIFF.
2
   Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
3
 
4
This file is part of GNU DIFF.
5
 
6
GNU DIFF is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU DIFF is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU DIFF; see the file COPYING.  If not, write to
18
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
 
20
#include "diff.h"
21
 
22
/* Rotate a value n bits to the left. */
23
#define UINT_BIT (sizeof (unsigned) * CHAR_BIT)
24
#define ROL(v, n) ((v) << (n) | (v) >> (UINT_BIT - (n)))
25
 
26
/* Given a hash value and a new character, return a new hash value. */
27
#define HASH(h, c) ((c) + ROL (h, 7))
28
 
29
/* Guess remaining number of lines from number N of lines so far,
30
   size S so far, and total size T.  */
31
#define GUESS_LINES(n,s,t) (((t) - (s)) / ((n) < 10 ? 32 : (s) / ((n)-1)) + 5)
32
 
33
/* Type used for fast prefix comparison in find_identical_ends.  */
34
#ifndef word
35
#define word int
36
#endif
37
 
38
/* Lines are put into equivalence classes (of lines that match in line_cmp).
39
   Each equivalence class is represented by one of these structures,
40
   but only while the classes are being computed.
41
   Afterward, each class is represented by a number.  */
42
struct equivclass
43
{
44
  int next;	/* Next item in this bucket. */
45
  unsigned hash;	/* Hash of lines in this class.  */
46
  char const *line;	/* A line that fits this class. */
47
  size_t length;	/* That line's length, not counting its newline.  */
48
};
49
 
50
/* Hash-table: array of buckets, each being a chain of equivalence classes.
51
   buckets[-1] is reserved for incomplete lines.  */
52
static int *buckets;
53
 
54
/* Number of buckets in the hash table array, not counting buckets[-1]. */
55
static int nbuckets;
56
 
57
/* Array in which the equivalence classes are allocated.
58
   The bucket-chains go through the elements in this array.
59
   The number of an equivalence class is its index in this array.  */
60
static struct equivclass *equivs;
61
 
62
/* Index of first free element in the array `equivs'.  */
63
static int equivs_index;
64
 
65
/* Number of elements allocated in the array `equivs'.  */
66
static int equivs_alloc;
67
 
68
static void find_and_hash_each_line PARAMS((struct file_data *));
69
static void find_identical_ends PARAMS((struct file_data[]));
70
static void prepare_text_end PARAMS((struct file_data *));
71
 
72
/* Check for binary files and compare them for exact identity.  */
73
 
74
/* Return 1 if BUF contains a non text character.
75
   SIZE is the number of characters in BUF.  */
76
 
77
#define binary_file_p(buf, size) (memchr (buf, '\0', size) != 0)
78
 
79
/* Get ready to read the current file.
80
   Return nonzero if SKIP_TEST is zero,
81
   and if it appears to be a binary file.  */
82
 
83
int
84
sip (current, skip_test)
85
     struct file_data *current;
86
     int skip_test;
87
{
88
  /* If we have a nonexistent file at this stage, treat it as empty.  */
89
  if (current->desc < 0)
90
    {
91
      /* Leave room for a sentinel.  */
92
      current->bufsize = sizeof (word);
93
      current->buffer = xmalloc (current->bufsize);
94
    }
95
  else
96
    {
97
      current->bufsize = STAT_BLOCKSIZE (current->stat);
98
      current->buffer = xmalloc (current->bufsize);
99
 
100
      if (! skip_test)
101
	{
102
	  /* Check first part of file to see if it's a binary file.  */
103
#if HAVE_SETMODE
104
	  int oldmode = setmode (current->desc, O_BINARY);
105
#endif
106
	  size_t n = read (current->desc, current->buffer, current->bufsize);
107
	  if (n == -1)
108
	    pfatal_with_name (current->name);
109
	  current->buffered_chars = n;
110
#if HAVE_SETMODE
111
	  if (oldmode != O_BINARY)
112
	    {
113
	      if (lseek (current->desc, - (off_t) n, SEEK_CUR) == -1)
114
		pfatal_with_name (current->name);
115
	      setmode (current->desc, oldmode);
116
	      current->buffered_chars = 0;
117
	    }
118
#endif
119
	  return binary_file_p (current->buffer, n);
120
	}
121
    }
122
 
123
  current->buffered_chars = 0;
124
  return 0;
125
}
126
 
127
/* Slurp the rest of the current file completely into memory.  */
128
 
129
void
130
slurp (current)
131
     struct file_data *current;
132
{
133
  size_t cc;
134
 
135
  if (current->desc < 0)
136
    /* The file is nonexistent.  */
137
    ;
138
  else if (S_ISREG (current->stat.st_mode))
139
    {
140
      /* It's a regular file; slurp in the rest all at once.  */
141
 
142
      /* Get the size out of the stat block.
143
	 Allocate enough room for appended newline and sentinel.  */
144
      cc = current->stat.st_size + 1 + sizeof (word);
145
      if (current->bufsize < cc)
146
	{
147
	  current->bufsize = cc;
148
	  current->buffer = xrealloc (current->buffer, cc);
149
	}
150
 
151
      if (current->buffered_chars < current->stat.st_size)
152
	{
153
	  cc = read (current->desc,
154
		     current->buffer + current->buffered_chars,
155
		     current->stat.st_size - current->buffered_chars);
156
	  if (cc == -1)
157
	    pfatal_with_name (current->name);
158
	  current->buffered_chars += cc;
159
	}
160
    }
161
  /* It's not a regular file; read it, growing the buffer as needed.  */
162
  else if (always_text_flag || current->buffered_chars != 0)
163
    {
164
      for (;;)
165
	{
166
	  if (current->buffered_chars == current->bufsize)
167
	    {
168
	      current->bufsize = current->bufsize * 2;
169
	      current->buffer = xrealloc (current->buffer, current->bufsize);
170
	    }
171
	  cc = read (current->desc,
172
		     current->buffer + current->buffered_chars,
173
		     current->bufsize - current->buffered_chars);
174
	  if (cc == 0)
175
	    break;
176
	  if (cc == -1)
177
	    pfatal_with_name (current->name);
178
	  current->buffered_chars += cc;
179
	}
180
      /* Allocate just enough room for appended newline and sentinel.  */
181
      current->bufsize = current->buffered_chars + 1 + sizeof (word);
182
      current->buffer = xrealloc (current->buffer, current->bufsize);
183
    }
184
}
185
 
186
/* Split the file into lines, simultaneously computing the equivalence class for
187
   each line. */
188
 
189
static void
190
find_and_hash_each_line (current)
191
     struct file_data *current;
192
{
193
  unsigned h;
194
  unsigned char const *p = (unsigned char const *) current->prefix_end;
195
  unsigned char c;
196
  int i, *bucket;
197
  size_t length;
198
 
199
  /* Cache often-used quantities in local variables to help the compiler.  */
200
  char const **linbuf = current->linbuf;
201
  int alloc_lines = current->alloc_lines;
202
  int line = 0;
203
  int linbuf_base = current->linbuf_base;
204
  int *cureqs = (int *) xmalloc (alloc_lines * sizeof (int));
205
  struct equivclass *eqs = equivs;
206
  int eqs_index = equivs_index;
207
  int eqs_alloc = equivs_alloc;
208
  char const *suffix_begin = current->suffix_begin;
209
  char const *bufend = current->buffer + current->buffered_chars;
210
  int use_line_cmp = ignore_some_line_changes;
211
 
212
  while ((char const *) p < suffix_begin)
213
    {
214
      char const *ip = (char const *) p;
215
 
216
      /* Compute the equivalence class for this line.  */
217
 
218
      h = 0;
219
 
220
      /* Hash this line until we find a newline. */
221
      if (ignore_case_flag)
222
	{
223
	  if (ignore_all_space_flag)
224
	    while ((c = *p++) != '\n')
225
	      {
226
		if (! ISSPACE (c))
227
		  h = HASH (h, ISUPPER (c) ? tolower (c) : c);
228
	      }
229
	  else if (ignore_space_change_flag)
230
	    while ((c = *p++) != '\n')
231
	      {
232
		if (ISSPACE (c))
233
		  {
234
		    for (;;)
235
		      {
236
			c = *p++;
237
			if (!ISSPACE (c))
238
			  break;
239
			if (c == '\n')
240
			  goto hashing_done;
241
		      }
242
		    h = HASH (h, ' ');
243
		  }
244
		/* C is now the first non-space.  */
245
		h = HASH (h, ISUPPER (c) ? tolower (c) : c);
246
	      }
247
	  else
248
	    while ((c = *p++) != '\n')
249
	      h = HASH (h, ISUPPER (c) ? tolower (c) : c);
250
	}
251
      else
252
	{
253
	  if (ignore_all_space_flag)
254
	    while ((c = *p++) != '\n')
255
	      {
256
		if (! ISSPACE (c))
257
		  h = HASH (h, c);
258
	      }
259
	  else if (ignore_space_change_flag)
260
	    while ((c = *p++) != '\n')
261
	      {
262
		if (ISSPACE (c))
263
		  {
264
		    for (;;)
265
		      {
266
			c = *p++;
267
			if (!ISSPACE (c))
268
			  break;
269
			if (c == '\n')
270
			  goto hashing_done;
271
		      }
272
		    h = HASH (h, ' ');
273
		  }
274
		/* C is now the first non-space.  */
275
		h = HASH (h, c);
276
	      }
277
	  else
278
	    while ((c = *p++) != '\n')
279
	      h = HASH (h, c);
280
	}
281
   hashing_done:;
282
 
283
      bucket = &buckets[h % nbuckets];
284
      length = (char const *) p - ip - 1;
285
 
286
      if ((char const *) p == bufend
287
	  && current->missing_newline
288
	  && ROBUST_OUTPUT_STYLE (output_style))
289
	{
290
	  /* This line is incomplete.  If this is significant,
291
	     put the line into bucket[-1].  */
292
	  if (! (ignore_space_change_flag | ignore_all_space_flag))
293
	    bucket = &buckets[-1];
294
 
295
	  /* Omit the inserted newline when computing linbuf later.  */
296
	  p--;
297
	  bufend = suffix_begin = (char const *) p;
298
	}
299
 
300
      for (i = *bucket;  ;  i = eqs[i].next)
301
	if (!i)
302
	  {
303
	    /* Create a new equivalence class in this bucket. */
304
	    i = eqs_index++;
305
	    if (i == eqs_alloc)
306
	      eqs = (struct equivclass *)
307
		      xrealloc (eqs, (eqs_alloc*=2) * sizeof(*eqs));
308
	    eqs[i].next = *bucket;
309
	    eqs[i].hash = h;
310
	    eqs[i].line = ip;
311
	    eqs[i].length = length;
312
	    *bucket = i;
313
	    break;
314
	  }
315
	else if (eqs[i].hash == h)
316
	  {
317
	    char const *eqline = eqs[i].line;
318
 
319
	    /* Reuse existing equivalence class if the lines are identical.
320
	       This detects the common case of exact identity
321
	       faster than complete comparison would.  */
322
	    if (eqs[i].length == length && memcmp (eqline, ip, length) == 0)
323
	      break;
324
 
325
	    /* Reuse existing class if line_cmp reports the lines equal.  */
326
	    if (use_line_cmp && line_cmp (eqline, ip) == 0)
327
	      break;
328
	  }
329
 
330
      /* Maybe increase the size of the line table. */
331
      if (line == alloc_lines)
332
	{
333
	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
334
	  alloc_lines = 2 * alloc_lines - linbuf_base;
335
	  cureqs = (int *) xrealloc (cureqs, alloc_lines * sizeof (*cureqs));
336
	  linbuf = (char const **) xrealloc (linbuf + linbuf_base,
337
					     (alloc_lines - linbuf_base)
338
					     * sizeof (*linbuf))
339
		   - linbuf_base;
340
	}
341
      linbuf[line] = ip;
342
      cureqs[line] = i;
343
      ++line;
344
    }
345
 
346
  current->buffered_lines = line;
347
 
348
  for (i = 0;  ;  i++)
349
    {
350
      /* Record the line start for lines in the suffix that we care about.
351
	 Record one more line start than lines,
352
	 so that we can compute the length of any buffered line.  */
353
      if (line == alloc_lines)
354
	{
355
	  /* Double (alloc_lines - linbuf_base) by adding to alloc_lines.  */
356
	  alloc_lines = 2 * alloc_lines - linbuf_base;
357
	  linbuf = (char const **) xrealloc (linbuf + linbuf_base,
358
					     (alloc_lines - linbuf_base)
359
					     * sizeof (*linbuf))
360
		   - linbuf_base;
361
	}
362
      linbuf[line] = (char const *) p;
363
 
364
      if ((char const *) p == bufend)
365
	break;
366
 
367
      if (context <= i && no_diff_means_no_output)
368
	break;
369
 
370
      line++;
371
 
372
      while (*p++ != '\n')
373
	;
374
    }
375
 
376
  /* Done with cache in local variables.  */
377
  current->linbuf = linbuf;
378
  current->valid_lines = line;
379
  current->alloc_lines = alloc_lines;
380
  current->equivs = cureqs;
381
  equivs = eqs;
382
  equivs_alloc = eqs_alloc;
383
  equivs_index = eqs_index;
384
}
385
 
386
/* Prepare the end of the text.  Make sure it's initialized.
387
   Make sure text ends in a newline,
388
   but remember that we had to add one.  */
389
 
390
static void
391
prepare_text_end (current)
392
     struct file_data *current;
393
{
394
  size_t buffered_chars = current->buffered_chars;
395
  char *p = current->buffer;
396
 
397
  if (buffered_chars == 0 || p[buffered_chars - 1] == '\n')
398
    current->missing_newline = 0;
399
  else
400
    {
401
      p[buffered_chars++] = '\n';
402
      current->buffered_chars = buffered_chars;
403
      current->missing_newline = 1;
404
    }
405
 
406
  /* Don't use uninitialized storage when planting or using sentinels.  */
407
  if (p)
408
    bzero (p + buffered_chars, sizeof (word));
409
}
410
 
411
/* Given a vector of two file_data objects, find the identical
412
   prefixes and suffixes of each object. */
413
 
414
static void
415
find_identical_ends (filevec)
416
     struct file_data filevec[];
417
{
418
  word *w0, *w1;
419
  char *p0, *p1, *buffer0, *buffer1;
420
  char const *end0, *beg0;
421
  char const **linbuf0, **linbuf1;
422
  int i, lines;
423
  size_t n0, n1, tem;
424
  int alloc_lines0, alloc_lines1;
425
  int buffered_prefix, prefix_count, prefix_mask;
426
 
427
  slurp (&filevec[0]);
428
  if (filevec[0].desc != filevec[1].desc)
429
    slurp (&filevec[1]);
430
  else
431
    {
432
      filevec[1].buffer = filevec[0].buffer;
433
      filevec[1].bufsize = filevec[0].bufsize;
434
      filevec[1].buffered_chars = filevec[0].buffered_chars;
435
    }
436
  for (i = 0; i < 2; i++)
437
    prepare_text_end (&filevec[i]);
438
 
439
  /* Find identical prefix.  */
440
 
441
  p0 = buffer0 = filevec[0].buffer;
442
  p1 = buffer1 = filevec[1].buffer;
443
 
444
  n0 = filevec[0].buffered_chars;
445
  n1 = filevec[1].buffered_chars;
446
 
447
  if (p0 == p1)
448
    /* The buffers are the same; sentinels won't work.  */
449
    p0 = p1 += n1;
450
  else
451
    {
452
      /* Insert end sentinels, in this case characters that are guaranteed
453
	 to make the equality test false, and thus terminate the loop.  */
454
 
455
      if (n0 < n1)
456
	p0[n0] = ~p1[n0];
457
      else
458
	p1[n1] = ~p0[n1];
459
 
460
      /* Loop until first mismatch, or to the sentinel characters.  */
461
 
462
      /* Compare a word at a time for speed.  */
463
      w0 = (word *) p0;
464
      w1 = (word *) p1;
465
      while (*w0++ == *w1++)
466
	;
467
      --w0, --w1;
468
 
469
      /* Do the last few bytes of comparison a byte at a time.  */
470
      p0 = (char *) w0;
471
      p1 = (char *) w1;
472
      while (*p0++ == *p1++)
473
	;
474
      --p0, --p1;
475
 
476
      /* Don't mistakenly count missing newline as part of prefix. */
477
      if (ROBUST_OUTPUT_STYLE (output_style)
478
	  && (buffer0 + n0 - filevec[0].missing_newline < p0)
479
	     !=
480
	     (buffer1 + n1 - filevec[1].missing_newline < p1))
481
	--p0, --p1;
482
    }
483
 
484
  /* Now P0 and P1 point at the first nonmatching characters.  */
485
 
486
  /* Skip back to last line-beginning in the prefix,
487
     and then discard up to HORIZON_LINES lines from the prefix.  */
488
  i = horizon_lines;
489
  while (p0 != buffer0 && (p0[-1] != '\n' || i--))
490
    --p0, --p1;
491
 
492
  /* Record the prefix.  */
493
  filevec[0].prefix_end = p0;
494
  filevec[1].prefix_end = p1;
495
 
496
  /* Find identical suffix.  */
497
 
498
  /* P0 and P1 point beyond the last chars not yet compared.  */
499
  p0 = buffer0 + n0;
500
  p1 = buffer1 + n1;
501
 
502
  if (! ROBUST_OUTPUT_STYLE (output_style)
503
      || filevec[0].missing_newline == filevec[1].missing_newline)
504
    {
505
      end0 = p0;	/* Addr of last char in file 0.  */
506
 
507
      /* Get value of P0 at which we should stop scanning backward:
508
	 this is when either P0 or P1 points just past the last char
509
	 of the identical prefix.  */
510
      beg0 = filevec[0].prefix_end + (n0 < n1 ? 0 : n0 - n1);
511
 
512
      /* Scan back until chars don't match or we reach that point.  */
513
      while (p0 != beg0)
514
	if (*--p0 != *--p1)
515
	  {
516
	    /* Point at the first char of the matching suffix.  */
517
	    ++p0, ++p1;
518
	    beg0 = p0;
519
	    break;
520
	  }
521
 
522
      /* Are we at a line-beginning in both files?  If not, add the rest of
523
	 this line to the main body.  Discard up to HORIZON_LINES lines from
524
	 the identical suffix.  Also, discard one extra line,
525
	 because shift_boundaries may need it.  */
526
      i = horizon_lines + !((buffer0 == p0 || p0[-1] == '\n')
527
			    &&
528
			    (buffer1 == p1 || p1[-1] == '\n'));
529
      while (i-- && p0 != end0)
530
	while (*p0++ != '\n')
531
	  ;
532
 
533
      p1 += p0 - beg0;
534
    }
535
 
536
  /* Record the suffix.  */
537
  filevec[0].suffix_begin = p0;
538
  filevec[1].suffix_begin = p1;
539
 
540
  /* Calculate number of lines of prefix to save.
541
 
542
     prefix_count == 0 means save the whole prefix;
543
     we need this with for options like -D that output the whole file.
544
     We also need it for options like -F that output some preceding line;
545
     at least we will need to find the last few lines,
546
     but since we don't know how many, it's easiest to find them all.
547
 
548
     Otherwise, prefix_count != 0.  Save just prefix_count lines at start
549
     of the line buffer; they'll be moved to the proper location later.
550
     Handle 1 more line than the context says (because we count 1 too many),
551
     rounded up to the next power of 2 to speed index computation.  */
552
 
553
  if (no_diff_means_no_output && ! function_regexp_list)
554
    {
555
      for (prefix_count = 1;  prefix_count < context + 1;  prefix_count *= 2)
556
	;
557
      prefix_mask = prefix_count - 1;
558
      alloc_lines0
559
	= prefix_count
560
	  + GUESS_LINES (0, 0, p0 - filevec[0].prefix_end)
561
	  + context;
562
    }
563
  else
564
    {
565
      prefix_count = 0;
566
      prefix_mask = ~0;
567
      alloc_lines0 = GUESS_LINES (0, 0, n0);
568
    }
569
 
570
  lines = 0;
571
  linbuf0 = (char const **) xmalloc (alloc_lines0 * sizeof (*linbuf0));
572
 
573
  /* If the prefix is needed, find the prefix lines.  */
574
  if (! (no_diff_means_no_output
575
	 && filevec[0].prefix_end == p0
576
	 && filevec[1].prefix_end == p1))
577
    {
578
      p0 = buffer0;
579
      end0 = filevec[0].prefix_end;
580
      while (p0 != end0)
581
	{
582
	  int l = lines++ & prefix_mask;
583
	  if (l == alloc_lines0)
584
	    linbuf0 = (char const **) xrealloc (linbuf0, (alloc_lines0 *= 2)
585
							 * sizeof(*linbuf0));
586
	  linbuf0[l] = p0;
587
	  while (*p0++ != '\n')
588
	    ;
589
	}
590
    }
591
  buffered_prefix = prefix_count && context < lines ? context : lines;
592
 
593
  /* Allocate line buffer 1.  */
594
  tem = prefix_count ? filevec[1].suffix_begin - buffer1 : n1;
595
 
596
  alloc_lines1
597
    = (buffered_prefix
598
       + GUESS_LINES (lines, filevec[1].prefix_end - buffer1, tem)
599
       + context);
600
  linbuf1 = (char const **) xmalloc (alloc_lines1 * sizeof (*linbuf1));
601
 
602
  if (buffered_prefix != lines)
603
    {
604
      /* Rotate prefix lines to proper location.  */
605
      for (i = 0;  i < buffered_prefix;  i++)
606
	linbuf1[i] = linbuf0[(lines - context + i) & prefix_mask];
607
      for (i = 0;  i < buffered_prefix;  i++)
608
	linbuf0[i] = linbuf1[i];
609
    }
610
 
611
  /* Initialize line buffer 1 from line buffer 0.  */
612
  for (i = 0; i < buffered_prefix; i++)
613
    linbuf1[i] = linbuf0[i] - buffer0 + buffer1;
614
 
615
  /* Record the line buffer, adjusted so that
616
     linbuf*[0] points at the first differing line.  */
617
  filevec[0].linbuf = linbuf0 + buffered_prefix;
618
  filevec[1].linbuf = linbuf1 + buffered_prefix;
619
  filevec[0].linbuf_base = filevec[1].linbuf_base = - buffered_prefix;
620
  filevec[0].alloc_lines = alloc_lines0 - buffered_prefix;
621
  filevec[1].alloc_lines = alloc_lines1 - buffered_prefix;
622
  filevec[0].prefix_lines = filevec[1].prefix_lines = lines;
623
}
624
 
625
/* Largest primes less than some power of two, for nbuckets.  Values range
626
   from useful to preposterous.  If one of these numbers isn't prime
627
   after all, don't blame it on me, blame it on primes (6) . . . */
628
static int const primes[] =
629
{
630
  509,
631
  1021,
632
  2039,
633
  4093,
634
  8191,
635
  16381,
636
  32749,
637
#if 32767 < INT_MAX
638
  65521,
639
  131071,
640
  262139,
641
  524287,
642
  1048573,
643
  2097143,
644
  4194301,
645
  8388593,
646
  16777213,
647
  33554393,
648
  67108859,			/* Preposterously large . . . */
649
  134217689,
650
  268435399,
651
  536870909,
652
  1073741789,
653
  2147483647,
654
#endif
655
 
656
};
657
 
658
/* Given a vector of two file_data objects, read the file associated
659
   with each one, and build the table of equivalence classes.
660
   Return 1 if either file appears to be a binary file.
661
   If PRETEND_BINARY is nonzero, pretend they are binary regardless.  */
662
 
663
int
664
read_files (filevec, pretend_binary)
665
     struct file_data filevec[];
666
     int pretend_binary;
667
{
668
  int i;
669
  int skip_test = always_text_flag | pretend_binary;
670
  int appears_binary = pretend_binary | sip (&filevec[0], skip_test);
671
 
672
  if (filevec[0].desc != filevec[1].desc)
673
    appears_binary |= sip (&filevec[1], skip_test | appears_binary);
674
  else
675
    {
676
      filevec[1].buffer = filevec[0].buffer;
677
      filevec[1].bufsize = filevec[0].bufsize;
678
      filevec[1].buffered_chars = filevec[0].buffered_chars;
679
    }
680
  if (appears_binary)
681
    {
682
#if HAVE_SETMODE
683
      setmode (filevec[0].desc, O_BINARY);
684
      setmode (filevec[1].desc, O_BINARY);
685
#endif
686
      return 1;
687
    }
688
 
689
  find_identical_ends (filevec);
690
 
691
  equivs_alloc = filevec[0].alloc_lines + filevec[1].alloc_lines + 1;
692
  equivs = (struct equivclass *) xmalloc (equivs_alloc * sizeof (struct equivclass));
693
  /* Equivalence class 0 is permanently safe for lines that were not
694
     hashed.  Real equivalence classes start at 1. */
695
  equivs_index = 1;
696
 
697
  for (i = 0;  primes[i] < equivs_alloc / 3;  i++)
698
    if (! primes[i])
699
      abort ();
700
  nbuckets = primes[i];
701
 
702
  buckets = (int *) xmalloc ((nbuckets + 1) * sizeof (*buckets));
703
  bzero (buckets++, (nbuckets + 1) * sizeof (*buckets));
704
 
705
  for (i = 0; i < 2; i++)
706
    find_and_hash_each_line (&filevec[i]);
707
 
708
  filevec[0].equiv_max = filevec[1].equiv_max = equivs_index;
709
 
710
  free (equivs);
711
  free (buckets - 1);
712
 
713
  return 0;
714
}