| 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>"; | 
| 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) | 
| 350 |  |  | 
| 351 |  | /* Compare two sets of header variables */ | 
| 352 |  | static int | 
| 353 | < | headers_match(LUTAB *hp1, LUTAB *hp2) | 
| 353 | > | headers_match() | 
| 354 |  | { | 
| 355 | < | int     ne = lu_doall(hp1, match_val, hp2); | 
| 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(hp2, NULL, NULL) - ne)) | 
| 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 */ | 
| 504 |  | static int | 
| 505 |  | compare_text() | 
| 506 |  | { | 
| 507 | < | char    l1buf[4096], l2buf[4096]; | 
| 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 | < | /* compare a line at a time */ | 
| 514 | < | while (fgets(l1buf, sizeof(l1buf), f1in)) { | 
| 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,0)) | 
| 516 | > | if (!*sskip2(l1buf.str,0)) | 
| 517 |  | continue;               /* ignore empty lines */ | 
| 518 | < | while (fgets(l2buf, sizeof(l2buf), f2in)) { | 
| 518 | > |  | 
| 519 | > | while (read_line(&l2buf, f2in)) { | 
| 520 |  | lin2cnt++; | 
| 521 | < | if (*sskip2(l2buf,0)) | 
| 521 | > | if (*sskip2(l2buf.str,0)) | 
| 522 |  | break;          /* found other non-empty line */ | 
| 523 |  | } | 
| 524 | < | if (feof(f2in)) { | 
| 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, l2buf)) { | 
| 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) { | 
| 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); | 
| 543 | > | lin1cnt, l1buf.str); | 
| 544 |  | printf("%s@%d:\t%s", f2name, | 
| 545 | < | lin2cnt, l2buf); | 
| 545 | > | lin2cnt, l2buf.str); | 
| 546 |  | } | 
| 547 |  | } | 
| 548 | + | free_line(&l1buf); free_line(&l2buf); | 
| 549 |  | return(0); | 
| 550 |  | } | 
| 551 |  | } | 
| 552 | < | /* check for EOF on input 2 */ | 
| 553 | < | while (fgets(l2buf, sizeof(l2buf), f2in)) { | 
| 554 | < | if (!*sskip2(l2buf,0)) | 
| 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 |  |  | 
| 775 |  | return(1); | 
| 776 |  | } | 
| 777 |  | ign_header |= !has_header(typ1);        /* check headers if indicated */ | 
| 778 | < | if (!ign_header && !headers_match(&hdr1, &hdr2)) | 
| 778 | > | if (!ign_header && !headers_match()) | 
| 779 |  | return(1); | 
| 780 | < | lu_done(&hdr1); lu_done(&hdr2); | 
| 780 | > | lu_done(&hdr1); lu_done(&hdr2);         /* done with header info. */ | 
| 781 |  | if (!ign_header & (report >= REP_WARN)) { | 
| 716 | – | if (typ1 == TYP_UNKNOWN) | 
| 717 | – | printf("%s: warning - unrecognized format, comparing as binary\n", | 
| 718 | – | progname); | 
| 782 |  | if (lin1cnt != lin2cnt) | 
| 783 |  | printf("%s: warning - headers are different lengths\n", | 
| 784 | + | progname); | 
| 785 | + | if (typ1 == TYP_UNKNOWN) | 
| 786 | + | printf("%s: warning - unrecognized format\n", | 
| 787 |  | progname); | 
| 788 |  | } | 
| 789 |  | if (report >= REP_VERBOSE) |