119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===- Support/FileUtilities.cpp - File System Utilities ------------------===// 219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// 319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// The LLVM Compiler Infrastructure 419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// 519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file is distributed under the University of Illinois Open Source 619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// License. See LICENSE.TXT for details. 719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// 819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===// 919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// 1019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file implements a family of utility functions which are useful for doing 1119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// various things with files. 1219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// 1319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===// 1419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 1519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/FileUtilities.h" 1619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/MemoryBuffer.h" 1719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/raw_ostream.h" 1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/Path.h" 1919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/system_error.h" 2019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/ADT/OwningPtr.h" 2119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/ADT/SmallString.h" 2219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include <cstdlib> 2319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include <cstring> 2419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include <cctype> 2519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanusing namespace llvm; 2619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 2719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic bool isSignedChar(char C) { 2819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return (C == '+' || C == '-'); 2919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 3019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 3119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic bool isExponentChar(char C) { 3219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman switch (C) { 3319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case 'D': // Strange exponential notation. 3419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case 'd': // Strange exponential notation. 3519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case 'e': 3619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case 'E': return true; 3719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman default: return false; 3819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 3919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 4019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 4119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic bool isNumberChar(char C) { 4219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman switch (C) { 4319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case '0': case '1': case '2': case '3': case '4': 4419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case '5': case '6': case '7': case '8': case '9': 4519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman case '.': return true; 4619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman default: return isSignedChar(C) || isExponentChar(C); 4719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 4819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 4919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 5019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic const char *BackupNumber(const char *Pos, const char *FirstChar) { 5119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If we didn't stop in the middle of a number, don't backup. 5219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (!isNumberChar(*Pos)) return Pos; 5319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 5419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Otherwise, return to the start of the number. 5519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman bool HasPeriod = false; 5619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (Pos > FirstChar && isNumberChar(Pos[-1])) { 5719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Backup over at most one period. 5819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Pos[-1] == '.') { 5919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (HasPeriod) 6019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman break; 6119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman HasPeriod = true; 6219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 6319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 6419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman --Pos; 6519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Pos > FirstChar && isSignedChar(Pos[0]) && !isExponentChar(Pos[-1])) 6619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman break; 6719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 6819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return Pos; 6919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 7019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 7119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// EndOfNumber - Return the first character that is not part of the specified 7219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// number. This assumes that the buffer is null terminated, so it won't fall 7319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// off the end. 7419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic const char *EndOfNumber(const char *Pos) { 7519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (isNumberChar(*Pos)) 7619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman ++Pos; 7719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return Pos; 7819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 7919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 8019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// CompareNumbers - compare two numbers, returning true if they are different. 8119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanstatic bool CompareNumbers(const char *&F1P, const char *&F2P, 8219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *F1End, const char *F2End, 8319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman double AbsTolerance, double RelTolerance, 8419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman std::string *ErrorMsg) { 8519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *F1NumEnd, *F2NumEnd; 8619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman double V1 = 0.0, V2 = 0.0; 8719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 8819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If one of the positions is at a space and the other isn't, chomp up 'til 8919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // the end of the space. 9019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (isspace(*F1P) && F1P != F1End) 9119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman ++F1P; 9219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (isspace(*F2P) && F2P != F2End) 9319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman ++F2P; 9419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 9519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If we stop on numbers, compare their difference. 9619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (!isNumberChar(*F1P) || !isNumberChar(*F2P)) { 9719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // The diff failed. 9819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F1NumEnd = F1P; 9919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F2NumEnd = F2P; 10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } else { 10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Note that some ugliness is built into this to permit support for numbers 10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // that use "D" or "d" as their exponential marker, e.g. "1.234D45". This 10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // occurs in 200.sixtrack in spec2k. 10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman V1 = strtod(F1P, const_cast<char**>(&F1NumEnd)); 10519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman V2 = strtod(F2P, const_cast<char**>(&F2NumEnd)); 10619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 10719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (*F1NumEnd == 'D' || *F1NumEnd == 'd') { 10819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Copy string into tmp buffer to replace the 'D' with an 'e'. 10919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman SmallString<200> StrTmp(F1P, EndOfNumber(F1NumEnd)+1); 11019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Strange exponential notation! 11119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman StrTmp[static_cast<unsigned>(F1NumEnd-F1P)] = 'e'; 11219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 11319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman V1 = strtod(&StrTmp[0], const_cast<char**>(&F1NumEnd)); 11419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F1NumEnd = F1P + (F1NumEnd-&StrTmp[0]); 11519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 11619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 11719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (*F2NumEnd == 'D' || *F2NumEnd == 'd') { 11819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Copy string into tmp buffer to replace the 'D' with an 'e'. 11919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman SmallString<200> StrTmp(F2P, EndOfNumber(F2NumEnd)+1); 12019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Strange exponential notation! 12119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman StrTmp[static_cast<unsigned>(F2NumEnd-F2P)] = 'e'; 12219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 12319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman V2 = strtod(&StrTmp[0], const_cast<char**>(&F2NumEnd)); 12419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F2NumEnd = F2P + (F2NumEnd-&StrTmp[0]); 12519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 12619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 12719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 12819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (F1NumEnd == F1P || F2NumEnd == F2P) { 12919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (ErrorMsg) { 13019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *ErrorMsg = "FP Comparison failed, not a numeric difference between '"; 13119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *ErrorMsg += F1P[0]; 13219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *ErrorMsg += "' and '"; 13319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *ErrorMsg += F2P[0]; 13419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *ErrorMsg += "'"; 13519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 13619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return true; 13719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 13819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 13919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Check to see if these are inside the absolute tolerance 14019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (AbsTolerance < std::abs(V1-V2)) { 14119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Nope, check the relative tolerance... 14219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman double Diff; 14319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (V2) 14419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman Diff = std::abs(V1/V2 - 1.0); 14519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman else if (V1) 14619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman Diff = std::abs(V2/V1 - 1.0); 14719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman else 14819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman Diff = 0; // Both zero. 14919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Diff > RelTolerance) { 15019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (ErrorMsg) { 15119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman raw_string_ostream(*ErrorMsg) 15219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman << "Compared: " << V1 << " and " << V2 << '\n' 15319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman << "abs. diff = " << std::abs(V1-V2) << " rel.diff = " << Diff << '\n' 15419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman << "Out of tolerance: rel/abs: " << RelTolerance << '/' 15519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman << AbsTolerance; 15619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 15719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return true; 15819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 15919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 16019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 16119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Otherwise, advance our read pointers to the end of the numbers. 16219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F1P = F1NumEnd; F2P = F2NumEnd; 16319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return false; 16419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 16519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 16619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// DiffFilesWithTolerance - Compare the two files specified, returning 0 if the 16719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// files match, 1 if they are different, and 2 if there is a file error. This 16819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// function differs from DiffFiles in that you can specify an absolete and 16919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// relative FP error that is allowed to exist. If you specify a string to fill 17019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// in for the error option, it will set the string to an error message if an 17119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// error occurs, allowing the caller to distinguish between a failed diff and a 17219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// file system error. 17319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman/// 17419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanint llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, 17519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const sys::PathWithStatus &FileB, 17619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman double AbsTol, double RelTol, 17719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman std::string *Error) { 17819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const sys::FileStatus *FileAStat = FileA.getFileStatus(false, Error); 17919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (!FileAStat) 18019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 2; 18119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const sys::FileStatus *FileBStat = FileB.getFileStatus(false, Error); 18219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (!FileBStat) 18319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 2; 18419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 18519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Check for zero length files because some systems croak when you try to 18619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // mmap an empty file. 18719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman size_t A_size = FileAStat->getSize(); 18819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman size_t B_size = FileBStat->getSize(); 18919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 19019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If they are both zero sized then they're the same 19119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (A_size == 0 && B_size == 0) 19219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 0; 19319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 19419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If only one of them is zero sized then they can't be the same 19519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if ((A_size == 0 || B_size == 0)) { 19619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Error) 19719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *Error = "Files differ: one is zero-sized, the other isn't"; 19819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 1; 19919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 20019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 20119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Now its safe to mmap the files into memory because both files 20219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // have a non-zero size. 20319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman error_code ec; 20419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman OwningPtr<MemoryBuffer> F1; 20519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) { 20619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Error) 20719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *Error = ec.message(); 20819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 2; 20919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 21019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman OwningPtr<MemoryBuffer> F2; 21119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (error_code ec = MemoryBuffer::getFile(FileB.c_str(), F2)) { 21219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Error) 21319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *Error = ec.message(); 21419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 2; 21519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 21619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 21719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Okay, now that we opened the files, scan them for the first difference. 21819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *File1Start = F1->getBufferStart(); 21919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *File2Start = F2->getBufferStart(); 22019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *File1End = F1->getBufferEnd(); 22119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *File2End = F2->getBufferEnd(); 22219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *F1P = File1Start; 22319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman const char *F2P = File2Start; 22419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 22519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Are the buffers identical? Common case: Handle this efficiently. 22619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (A_size == B_size && 22719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman std::memcmp(File1Start, File2Start, A_size) == 0) 22819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 0; 22919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 23019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Otherwise, we are done a tolerances are set. 23119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (AbsTol == 0 && RelTol == 0) { 23219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (Error) 23319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman *Error = "Files differ without tolerance allowance"; 23419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return 1; // Files different! 23519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 23619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 23719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman bool CompareFailed = false; 23819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (1) { 23919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Scan for the end of file or next difference. 24019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman while (F1P < File1End && F2P < File2End && *F1P == *F2P) 24119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman ++F1P, ++F2P; 24219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 24319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (F1P >= File1End || F2P >= File2End) break; 24419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 24519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Okay, we must have found a difference. Backup to the start of the 24619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // current number each stream is at so that we can compare from the 24719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // beginning. 24819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F1P = BackupNumber(F1P, File1Start); 24919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F2P = BackupNumber(F2P, File2Start); 25019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 25119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Now that we are at the start of the numbers, compare them, exiting if 25219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // they don't match. 25319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) { 25419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman CompareFailed = true; 25519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman break; 25619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 25719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 25819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 25919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Okay, we reached the end of file. If both files are at the end, we 26019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // succeeded. 26119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman bool F1AtEnd = F1P >= File1End; 26219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman bool F2AtEnd = F2P >= File2End; 26319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (!CompareFailed && (!F1AtEnd || !F2AtEnd)) { 26419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Else, we might have run off the end due to a number: backup and retry. 26519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (F1AtEnd && isNumberChar(F1P[-1])) --F1P; 26619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (F2AtEnd && isNumberChar(F2P[-1])) --F2P; 26719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F1P = BackupNumber(F1P, File1Start); 26819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman F2P = BackupNumber(F2P, File2Start); 26919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 27019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // Now that we are at the start of the numbers, compare them, exiting if 27119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // they don't match. 27219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) 27319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman CompareFailed = true; 27419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 27519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman // If we found the end, we succeeded. 27619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman if (F1P < File1End || F2P < File2End) 27719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman CompareFailed = true; 27819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman } 27919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman 28019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman return CompareFailed; 28119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman} 282