ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/radcompare.c
Revision: 2.15
Committed: Sat Oct 20 15:17:27 2018 UTC (5 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.14: +12 -3 lines
Log Message:
Added warning about too-long input lines

File Contents

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