ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/radcompare.c
Revision: 2.12
Committed: Fri Oct 19 22:15:30 2018 UTC (5 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +74 -41 lines
Log Message:
Dynamic input line buffers up to 100 MBytes

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: radcompare.c,v 2.11 2018/10/19 20:32:16 greg Exp $";
3 #endif
4 /*
5 * Compare Radiance files for significant differences
6 *
7 * G. Ward
8 */
9
10 #include <stdlib.h>
11 #include <math.h>
12 #include <ctype.h>
13 #include "platform.h"
14 #include "rtio.h"
15 #include "resolu.h"
16 #include "color.h"
17 #include "lookup.h"
18 /* Reporting levels */
19 #define REP_QUIET 0 /* no reporting */
20 #define REP_ERROR 1 /* report errors only */
21 #define REP_WARN 2 /* report warnings as well */
22 #define REP_VERBOSE 3 /* verbose reporting */
23
24 int report = REP_WARN; /* reporting level */
25
26 int ign_header = 0; /* ignore header differences? */
27
28 double rel_min = 1e-5; /* positive for relative comparisons */
29
30 double rms_lim = 0.01; /* RMS difference limit */
31
32 double max_lim = 0.25; /* difference limit if non-negative */
33
34 int lin1cnt=0, lin2cnt=0; /* file line position */
35
36 const char nsuffix[10][3] = { /* 1st, 2nd, 3rd, etc. */
37 "th","st","nd","rd","th","th","th","th","th","th"
38 };
39 #define num_sfx(n) nsuffix[(n)%10]
40
41 /* file types */
42 const char *file_type[] = {
43 "Unrecognized",
44 "TEXT_generic",
45 "ascii",
46 COLRFMT,
47 CIEFMT,
48 "float",
49 "double",
50 "BSDF_RBFmesh",
51 "Radiance_octree",
52 "Radiance_tmesh",
53 "BINARY_unknown",
54 NULL /* terminator */
55 };
56 /* keep consistent with above */
57 enum {TYP_UNKNOWN, TYP_TEXT, TYP_ASCII, TYP_RGBE, TYP_XYZE, TYP_FLOAT,
58 TYP_DOUBLE, TYP_RBFMESH, TYP_OCTREE, TYP_TMESH, TYP_BINARY};
59
60 #define has_header(t) (!( 1L<<(t) & (1L<<TYP_TEXT | 1L<<TYP_BINARY) ))
61
62 /* header variables to always ignore */
63 const char *hdr_ignkey[] = {
64 "SOFTWARE",
65 "CAPDATE",
66 "GMT",
67 NULL /* terminator */
68 };
69 /* header variable settings */
70 LUTAB hdr1 = LU_SINIT(free,free);
71 LUTAB hdr2 = LU_SINIT(free,free);
72
73 /* advance appropriate file line count */
74 #define adv_linecnt(htp) (lin1cnt += (htp == &hdr1), \
75 lin2cnt += (htp == &hdr2))
76
77 typedef struct { /* dynamic line buffer */
78 char *ptr;
79 int len;
80 int siz;
81 } LINEBUF;
82
83 #define init_line(bp) ((bp)->ptr = NULL, (bp)->siz = 0)
84 /* 100 MByte limit on line buffer */
85 #define MAXBUF (100L<<20)
86
87 /* input files */
88 char *progname = NULL;
89 const char stdin_name[] = "<stdin>";
90 const char *f1name=NULL, *f2name=NULL;
91 FILE *f1in=NULL, *f2in=NULL;
92
93 /* running real differences */
94 double diff2sum = 0;
95 long nsum = 0;
96
97 /* Report usage and exit */
98 static void
99 usage()
100 {
101 fputs("Usage: ", stderr);
102 fputs(progname, stderr);
103 fputs(" [-h][-s|-w|-v][-rel min_test][-rms epsilon][-max epsilon] reference test\n",
104 stderr);
105 exit(2);
106 }
107
108 /* Read a text line, increasing buffer size as necessary */
109 static int
110 read_line(LINEBUF *bp, FILE *fp)
111 {
112 bp->len = 0;
113 if (!bp->ptr) {
114 bp->ptr = (char *)malloc(bp->siz = 512);
115 if (!bp->ptr)
116 goto memerr;
117 }
118 while (fgets(bp->ptr + bp->len, bp->siz - bp->len, fp)) {
119 bp->len += strlen(bp->ptr + bp->len);
120 if (bp->ptr[bp->len-1] == '\n')
121 break; /* found EOL */
122 if (bp->len < bp->siz - 4)
123 continue; /* at EOF? */
124 if (bp->siz >= MAXBUF)
125 break; /* don't go to extremes */
126 if ((bp->siz += bp->siz/2) > MAXBUF)
127 bp->siz = MAXBUF;
128 bp->ptr = (char *)realloc(bp->ptr, bp->siz);
129 if (!bp->ptr)
130 goto memerr;
131 }
132 return(bp->len);
133 memerr:
134 fprintf(stderr,
135 "%s: out of memory in read_line() allocating %d byte buffer\n",
136 progname, bp->siz);
137 exit(2);
138 }
139
140 /* Free line buffer */
141 static void
142 free_line(LINEBUF *bp)
143 {
144 bp->len = 0;
145 if (!bp->ptr) return;
146 free(bp->ptr);
147 bp->ptr = NULL;
148 }
149
150 /* Get type ID from name (or 0 if not found) */
151 static int
152 xlate_type(const char *nm)
153 {
154 int i;
155
156 if (!nm || !*nm)
157 return(TYP_UNKNOWN);
158 for (i = 1; file_type[i]; i++)
159 if (!strcmp(nm, file_type[i]))
160 return(i);
161 return(TYP_UNKNOWN);
162 }
163
164 /* Compare real values and keep track of differences */
165 static int
166 real_check(double r1, double r2)
167 {
168 double diff2 = (r1 - r2)*(r1 - r2);
169
170 if (rel_min > 0) { /* doing relative differences? */
171 double av2 = .25*(r1*r1 + 2.*fabs(r1*r2) + r2*r2);
172 if (av2 > rel_min*rel_min)
173 diff2 /= av2;
174 }
175 if (max_lim >= 0 && diff2 > max_lim*max_lim) {
176 if (report != REP_QUIET)
177 printf(
178 "%s: %sdifference between %.8g and %.8g exceeds epsilon of %.8g\n",
179 progname,
180 (rel_min > 0) ? "relative " : "",
181 r1, r2, max_lim);
182 return(0);
183 }
184 diff2sum += diff2;
185 nsum++;
186 return(1);
187 }
188
189 /* Compare two color values for equivalence */
190 static int
191 color_check(COLOR c1, COLOR c2)
192 {
193 int p;
194
195 if (!real_check(colval(c1,RED)+colval(c1,GRN)+colval(c1,BLU)*(1./3.),
196 colval(c2,RED)+colval(c2,GRN)+colval(c2,BLU))*(1./3.))
197 return(0);
198
199 p = (colval(c1,GRN) > colval(c1,RED)) ? GRN : RED;
200 if (colval(c1,BLU) > colval(c1,p)) p = BLU;
201
202 return(real_check(colval(c1,p), colval(c2,p)));
203 }
204
205 /* Compare two strings for equivalence */
206 static int
207 equiv_string(char *s1, char *s2)
208 {
209 #define CLS_STR 0
210 #define CLS_INT 1
211 #define CLS_FLT 2
212 /* skip whitespace at beginning */
213 while (isspace(*s1)) s1++;
214 while (isspace(*s2)) s2++;
215 while (*s1) { /* check each word */
216 int inquote;
217 if (!*s2) /* unexpected EOL in s2? */
218 return(0);
219 inquote = *s1;
220 if ((inquote != '\'') & (inquote != '"'))
221 inquote = 0;
222 if (inquote) { /* quoted text must match exactly */
223 if (*s1++ != *s2++)
224 return(0);
225 while (*s1 != inquote) {
226 if (!*s1)
227 return(0);
228 if (*s1++ != *s2++)
229 return(0);
230 }
231 s1++;
232 if (*s2++ != inquote)
233 return(0);
234 } else { /* else classify word type */
235 char *s1s = s1;
236 char *s2s = s2;
237 int cls = CLS_STR;
238 s1 = sskip(s1);
239 s2 = sskip(s2);
240 if (iskip(s1s) == s1) {
241 if (iskip(s2s) == s2)
242 cls = CLS_INT;
243 else if (fskip(s2s) == s2)
244 cls = CLS_FLT;
245 } else if (fskip(s1s) == s1) {
246 if (fskip(s2s) != s2)
247 return(0);
248 cls = CLS_FLT;
249 }
250 switch (cls) {
251 case CLS_INT: /* strncmp() faster */
252 case CLS_STR:
253 if (s1 - s1s != s2 - s2s)
254 return(0);
255 if (strncmp(s1s, s2s, s1 - s1s))
256 return(0);
257 break;
258 case CLS_FLT:
259 if (!real_check(atof(s1s), atof(s2s)))
260 return(0);
261 break;
262 }
263 }
264 while (isspace(*s1)) s1++;
265 while (isspace(*s2)) s2++;
266 }
267 return(!*s2); /* match if we reached the end of s2, too */
268 #undef CLS_STR
269 #undef CLS_INT
270 #undef CLS_FLT
271 }
272
273 /* Check if string is var=value pair and set if not in ignore list */
274 static int
275 setheadvar(char *val, void *p)
276 {
277 LUTAB *htp = (LUTAB *)p;
278 LUENT *tep;
279 char *key;
280 int kln, vln;
281 int n;
282
283 adv_linecnt(htp); /* side-effect is to count lines */
284 if (!isalpha(*val)) /* key must start line */
285 return(0);
286 key = val++;
287 while (*val && !isspace(*val) & (*val != '='))
288 val++;
289 kln = val - key;
290 while (isspace(*val)) /* check for value */
291 *val++ = '\0';
292 if (*val != '=')
293 return(0);
294 *val++ = '\0';
295 while (isspace(*val))
296 val++;
297 if (!*val) /* nothing set? */
298 return(0);
299 /* check if key to ignore */
300 for (n = 0; hdr_ignkey[n]; n++)
301 if (!strcmp(key, hdr_ignkey[n]))
302 return(0);
303 vln = strlen(val); /* eliminate space and newline at end */
304 while (isspace(val[--vln]))
305 ;
306 val[++vln] = '\0';
307 if (!(tep = lu_find(htp, key)))
308 return(-1); /* memory allocation error */
309 if (!tep->key)
310 tep->key = strcpy(malloc(kln+1), key);
311 if (tep->data)
312 free(tep->data);
313 tep->data = strcpy(malloc(vln+1), val);
314 return(1);
315 }
316
317 /* Lookup correspondent in other header */
318 static int
319 match_val(const LUENT *ep1, void *p2)
320 {
321 const LUENT *ep2 = lu_find((LUTAB *)p2, ep1->key);
322 if (!ep2 || !ep2->data) {
323 if (report != REP_QUIET)
324 printf("%s: variable '%s' missing in '%s'\n",
325 progname, ep1->key, f2name);
326 return(-1);
327 }
328 if (!equiv_string((char *)ep1->data, (char *)ep2->data)) {
329 if (report != REP_QUIET) {
330 printf("%s: header variable '%s' has different values\n",
331 progname, ep1->key);
332 if (report >= REP_VERBOSE) {
333 printf("%s: %s=%s\n", f1name,
334 ep1->key, (char *)ep1->data);
335 printf("%s: %s=%s\n", f2name,
336 ep2->key, (char *)ep2->data);
337 }
338 }
339 return(-1);
340 }
341 return(1); /* good match */
342 }
343
344 /* Compare two sets of header variables */
345 static int
346 headers_match()
347 {
348 int ne = lu_doall(&hdr1, match_val, &hdr2);
349 if (ne < 0)
350 return(0); /* something didn't match! */
351 /* non-fatal if second header has extra */
352 if (report >= REP_WARN && (ne = lu_doall(&hdr2, NULL, NULL) - ne))
353 printf("%s: warning - '%s' has %d extra header setting(s)\n",
354 progname, f2name, ne);
355 return(1); /* good match */
356 }
357
358 /* Check generic input to determine if it is binary, -1 on error */
359 static int
360 input_is_binary(FILE *fin)
361 {
362 int n = 0;
363 int c = 0;
364
365 while ((c = getc(fin)) != EOF) {
366 ++n;
367 if (!c | (c > 127))
368 break; /* non-ascii character */
369 if (n >= 10240)
370 break; /* enough to be confident */
371 }
372 if (!n)
373 return(-1); /* first read failed */
374 if (fseek(fin, 0L, 0) < 0)
375 return(-1); /* rewind failed */
376 return(!c | (c > 127));
377 }
378
379 /* Identify and return data type from header (if one) */
380 static int
381 identify_type(const char *name, FILE *fin, LUTAB *htp)
382 {
383 extern const char HDRSTR[];
384 int c;
385 /* check magic header start */
386 if ((c = getc(fin)) != HDRSTR[0]) {
387 if (c == EOF) goto badeof;
388 ungetc(c, fin);
389 c = 0;
390 } else if ((c = getc(fin)) != HDRSTR[1]) {
391 if (c == EOF) goto badeof;
392 ungetc(c, fin); ungetc(HDRSTR[0], fin);
393 c = 0;
394 }
395 if (c) { /* appears to have a header */
396 char sbuf[32];
397 if (!fgets(sbuf, sizeof(sbuf), fin))
398 goto badeof;
399 adv_linecnt(htp); /* for #?ID string */
400 if (report >= REP_WARN && strncmp(sbuf, "RADIANCE", 8)) {
401 fputs(name, stdout);
402 fputs(": warning - unexpected header ID: ", stdout);
403 fputs(sbuf, stdout);
404 }
405 if (getheader(fin, setheadvar, htp) < 0) {
406 fputs(name, stderr);
407 fputs(": unknown error reading header\n", stderr);
408 return(-1);
409 }
410 adv_linecnt(htp); /* for trailing emtpy line */
411 return(xlate_type((const char *)lu_find(htp,"FORMAT")->data));
412 }
413 c = input_is_binary(fin); /* else peek to see if binary */
414 if (c < 0) {
415 fputs(name, stderr);
416 fputs(": read/seek error\n", stderr);
417 return(-1);
418 }
419 if (c)
420 return(TYP_BINARY);
421 SET_FILE_TEXT(fin); /* originally set to binary */
422 return(TYP_TEXT);
423 badeof:
424 if (report != REP_QUIET) {
425 fputs(name, stdout);
426 fputs(": unexpected end-of-file\n", stdout);
427 }
428 return(-1);
429 }
430
431 /* Check that overall RMS error is below threshold */
432 static int
433 good_RMS()
434 {
435 if (!nsum)
436 return(1);
437 if (diff2sum/(double)nsum > rms_lim*rms_lim) {
438 if (report != REP_QUIET)
439 printf(
440 "%s: %sRMS difference between '%s' and '%s' of %.5g exceeds limit of %.5g\n",
441 progname,
442 (rel_min > 0) ? "relative " : "",
443 f1name, f2name,
444 sqrt(diff2sum/(double)nsum), rms_lim);
445 return(0);
446 }
447 if (report >= REP_VERBOSE)
448 printf("%s: %sRMS difference of reals in '%s' and '%s' is %.5g\n",
449 progname, (rel_min > 0) ? "relative " : "",
450 f1name, f2name, sqrt(diff2sum/(double)nsum));
451 return(1);
452 }
453
454 /* Compare two inputs as generic binary files */
455 static int
456 compare_binary()
457 {
458 int c1=0, c2=0;
459
460 if (report >= REP_VERBOSE) {
461 fputs(progname, stdout);
462 fputs(": comparing inputs as binary\n", stdout);
463 }
464 for ( ; ; ) { /* exact byte matching */
465 c1 = getc(f1in);
466 c2 = getc(f2in);
467 if (c1 == EOF) {
468 if (c2 == EOF)
469 return(1); /* success! */
470 if (report != REP_QUIET) {
471 fputs(f1name, stdout);
472 fputs(": unexpected end-of-file\n", stdout);
473 }
474 return(0);
475 }
476 if (c2 == EOF) {
477 if (report != REP_QUIET) {
478 fputs(f2name, stdout);
479 fputs(": unexpected end-of-file\n", stdout);
480 }
481 return(0);
482 }
483 if (c1 != c2)
484 break; /* quit and report difference */
485 }
486 if (report == REP_QUIET)
487 return(0);
488 printf("%s: binary files '%s' and '%s' differ at byte offset %ld|%ld\n",
489 progname, f1name, f2name, ftell(f1in), ftell(f2in));
490 if (report >= REP_VERBOSE)
491 printf("%s: byte in '%s' is 0x%X, byte in '%s' is 0x%X\n",
492 progname, f1name, c1, f2name, c2);
493 return(0);
494 }
495
496 /* Compare two inputs as generic text files */
497 static int
498 compare_text()
499 {
500 LINEBUF l1buf, l2buf;
501
502 if (report >= REP_VERBOSE) {
503 fputs(progname, stdout);
504 fputs(": comparing inputs as ASCII text\n", stdout);
505 }
506 init_line(&l1buf); init_line(&l2buf); /* compare a line at a time */
507 while (read_line(&l1buf, f1in)) {
508 lin1cnt++;
509 if (!*sskip2(l1buf.ptr,0))
510 continue; /* ignore empty lines */
511
512 while (read_line(&l2buf, f2in)) {
513 lin2cnt++;
514 if (*sskip2(l2buf.ptr,0))
515 break; /* found other non-empty line */
516 }
517 if (feof(f2in)) {
518 if (report != REP_QUIET) {
519 fputs(f2name, stdout);
520 fputs(": unexpected end-of-file\n", stdout);
521 }
522 free_line(&l1buf); free_line(&l2buf);
523 return(0);
524 }
525 /* compare non-empty lines */
526 if (!equiv_string(l1buf.ptr, l2buf.ptr)) {
527 if (report != REP_QUIET) {
528 printf("%s: inputs '%s' and '%s' differ at line %d|%d\n",
529 progname, f1name, f2name,
530 lin1cnt, lin2cnt);
531 if ( report >= REP_VERBOSE &&
532 (l1buf.len < 256) &
533 (l2buf.len < 256) ) {
534 fputs("------------- Mismatch -------------\n", stdout);
535 printf("%s@%d:\t%s", f1name,
536 lin1cnt, l1buf.ptr);
537 printf("%s@%d:\t%s", f2name,
538 lin2cnt, l2buf.ptr);
539 }
540 }
541 free_line(&l1buf); free_line(&l2buf);
542 return(0);
543 }
544 }
545 /* check for EOF on input 2 */
546 while (read_line(&l2buf, f2in)) {
547 if (!*sskip2(l2buf.ptr,0))
548 continue;
549 if (report != REP_QUIET) {
550 fputs(f1name, stdout);
551 fputs(": unexpected end-of-file\n", stdout);
552 }
553 free_line(&l1buf); free_line(&l2buf);
554 return(0);
555 }
556 free_line(&l1buf); free_line(&l2buf);
557 return(good_RMS()); /* final check for reals */
558 }
559
560 /* Compare two inputs that are known to be RGBE or XYZE images */
561 static int
562 compare_hdr()
563 {
564 RESOLU rs1, rs2;
565 COLOR *scan1, *scan2;
566 int x, y;
567
568 if (report >= REP_VERBOSE) {
569 fputs(progname, stdout);
570 fputs(": comparing inputs as HDR images\n", stdout);
571 }
572 fgetsresolu(&rs1, f1in);
573 fgetsresolu(&rs2, f2in);
574 if (rs1.rt != rs2.rt) {
575 if (report != REP_QUIET)
576 printf(
577 "%s: Images '%s' and '%s' have different pixel ordering\n",
578 progname, f1name, f2name);
579 return(0);
580 }
581 if ((rs1.xr != rs2.xr) | (rs1.yr != rs2.yr)) {
582 if (report != REP_QUIET)
583 printf(
584 "%s: Images '%s' and '%s' are different sizes\n",
585 progname, f1name, f2name);
586 return(0);
587 }
588 scan1 = (COLOR *)malloc(scanlen(&rs1)*sizeof(COLOR));
589 scan2 = (COLOR *)malloc(scanlen(&rs2)*sizeof(COLOR));
590 if (!scan1 | !scan2) {
591 fprintf(stderr, "%s: out of memory in compare_hdr()\n", progname);
592 exit(2);
593 }
594 for (y = 0; y < numscans(&rs1); y++) {
595 if ((freadscan(scan1, scanlen(&rs1), f1in) < 0) |
596 (freadscan(scan2, scanlen(&rs2), f2in) < 0)) {
597 if (report != REP_QUIET)
598 printf("%s: unexpected end-of-file\n",
599 progname);
600 free(scan1);
601 free(scan2);
602 return(0);
603 }
604 for (x = 0; x < scanlen(&rs1); x++) {
605 if (color_check(scan1[x], scan2[x]))
606 continue;
607 if (report != REP_QUIET) {
608 printf(
609 "%s: pixels at scanline %d offset %d differ\n",
610 progname, y, x);
611 if (report >= REP_VERBOSE) {
612 printf("%s: (R,G,B)=(%g,%g,%g)\n",
613 f1name, colval(scan1[x],RED),
614 colval(scan1[x],GRN),
615 colval(scan1[x],BLU));
616 printf("%s: (R,G,B)=(%g,%g,%g)\n",
617 f2name, colval(scan2[x],RED),
618 colval(scan2[x],GRN),
619 colval(scan2[x],BLU));
620 }
621 }
622 free(scan1);
623 free(scan2);
624 return(0);
625 }
626 }
627 free(scan1);
628 free(scan2);
629 return(good_RMS()); /* final check of RMS */
630 }
631
632 /* Compare two inputs that are known to be 32-bit floating-point data */
633 static int
634 compare_float()
635 {
636 long nread = 0;
637 float f1, f2;
638
639 if (report >= REP_VERBOSE) {
640 fputs(progname, stdout);
641 fputs(": comparing inputs as 32-bit IEEE floats\n", stdout);
642 }
643 while (getbinary(&f1, sizeof(f1), 1, f1in)) {
644 if (!getbinary(&f2, sizeof(f2), 1, f2in))
645 goto badeof;
646 ++nread;
647 if (real_check(f1, f2))
648 continue;
649 if (report != REP_QUIET)
650 printf("%s: %ld%s float values differ\n",
651 progname, nread, num_sfx(nread));
652 return(0);
653 }
654 if (!getbinary(&f2, sizeof(f2), 1, f2in))
655 return(good_RMS()); /* final check of RMS */
656 badeof:
657 if (report != REP_QUIET)
658 printf("%s: unexpected end-of-file\n", progname);
659 return(0);
660 }
661
662 /* Compare two inputs that are known to be 64-bit floating-point data */
663 static int
664 compare_double()
665 {
666 long nread = 0;
667 double f1, f2;
668
669 if (report >= REP_VERBOSE) {
670 fputs(progname, stdout);
671 fputs(": comparing inputs as 64-bit IEEE doubles\n", stdout);
672 }
673 while (getbinary(&f1, sizeof(f1), 1, f1in)) {
674 if (!getbinary(&f2, sizeof(f2), 1, f2in))
675 goto badeof;
676 ++nread;
677 if (real_check(f1, f2))
678 continue;
679 if (report != REP_QUIET)
680 printf("%s: %ld%s double values differ\n",
681 progname, nread, num_sfx(nread));
682 return(0);
683 }
684 if (!getbinary(&f2, sizeof(f2), 1, f2in))
685 return(good_RMS()); /* final check of RMS */
686 badeof:
687 if (report != REP_QUIET)
688 printf("%s: unexpected end-of-file\n", progname);
689 return(0);
690 }
691
692 /* Compare two Radiance files for equivalence */
693 int
694 main(int argc, char *argv[])
695 {
696 int typ1, typ2;
697 int a;
698
699 progname = argv[0];
700 for (a = 1; a < argc && argv[a][0] == '-'; a++) {
701 switch (argv[a][1]) {
702 case 'h': /* ignore header info. */
703 ign_header = !ign_header;
704 continue;
705 case 's': /* silent operation */
706 report = REP_QUIET;
707 continue;
708 case 'w': /* turn off warnings */
709 if (report > REP_ERROR)
710 report = REP_ERROR;
711 continue;
712 case 'v': /* turn on verbose mode */
713 report = REP_VERBOSE;
714 continue;
715 case 'm': /* maximum epsilon */
716 max_lim = atof(argv[++a]);
717 continue;
718 case 'r':
719 if (argv[a][2] == 'e') /* relative difference */
720 rel_min = atof(argv[++a]);
721 else if (argv[a][2] == 'm') /* RMS limit */
722 rms_lim = atof(argv[++a]);
723 else
724 usage();
725 continue;
726 case '\0': /* first file from stdin */
727 f1in = stdin;
728 f1name = stdin_name;
729 break;
730 default:
731 usage();
732 }
733 break;
734 }
735 if (a != argc-2) /* make sure of two inputs */
736 usage();
737 if (!strcmp(argv[a], argv[a+1])) { /* inputs are same? */
738 if (report >= REP_WARN)
739 printf("%s: warning - identical inputs given\n",
740 progname);
741 return(0);
742 }
743 if (!f1name) f1name = argv[a];
744 if (!f2name) f2name = argv[a+1];
745 /* open inputs */
746 SET_FILE_BINARY(stdin); /* in case we're using it */
747 if (!f1in && !(f1in = fopen(f1name, "rb"))) {
748 fprintf(stderr, "%s: cannot open for reading\n", f1name);
749 return(2);
750 }
751 if (!strcmp(f2name, "-")) {
752 f2in = stdin;
753 f2name = stdin_name;
754 } else if (!(f2in = fopen(f2name, "rb"))) {
755 fprintf(stderr, "%s: cannot open for reading\n", f2name);
756 return(2);
757 }
758 /* load headers */
759 if ((typ1 = identify_type(f1name, f1in, &hdr1)) < 0)
760 return(2);
761 if ((typ2 = identify_type(f2name, f2in, &hdr2)) < 0)
762 return(2);
763 if (typ1 != typ2) {
764 if (report != REP_QUIET)
765 printf("%s: '%s' is %s and '%s' is %s\n",
766 progname, f1name, file_type[typ1],
767 f2name, file_type[typ2]);
768 return(1);
769 }
770 ign_header |= !has_header(typ1); /* check headers if indicated */
771 if (!ign_header && !headers_match())
772 return(1);
773 lu_done(&hdr1); lu_done(&hdr2);
774 if (!ign_header & (report >= REP_WARN)) {
775 if (typ1 == TYP_UNKNOWN)
776 printf("%s: warning - unrecognized format, comparing as binary\n",
777 progname);
778 if (lin1cnt != lin2cnt)
779 printf("%s: warning - headers are different lengths\n",
780 progname);
781 }
782 if (report >= REP_VERBOSE)
783 printf("%s: input file type is %s\n",
784 progname, file_type[typ1]);
785
786 switch (typ1) { /* compare based on type */
787 case TYP_BINARY:
788 case TYP_TMESH:
789 case TYP_OCTREE:
790 case TYP_RBFMESH:
791 case TYP_UNKNOWN:
792 return( !compare_binary() );
793 case TYP_TEXT:
794 case TYP_ASCII:
795 return( !compare_text() );
796 case TYP_RGBE:
797 case TYP_XYZE:
798 return( !compare_hdr() );
799 case TYP_FLOAT:
800 return( !compare_float() );
801 case TYP_DOUBLE:
802 return( !compare_double() );
803 }
804 return(1);
805 }