ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/radcompare.c
Revision: 2.18
Committed: Sat Dec 1 21:09:53 2018 UTC (5 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.17: +2 -1 lines
Log Message:
Added FRAME to ignored header variables

File Contents

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