-bool llvm::MakeFileExecutable(const std::string &Filename) {
- return AddPermissionsBits(Filename, 0111);
-}
-
-/// MakeFileReadable - Make the file named Filename readable by
-/// setting whichever read permissions bits the process's current
-/// umask would allow. Filename must name an existing file or
-/// directory. Returns true on success, false on error.
-///
-bool llvm::MakeFileReadable(const std::string &Filename) {
- return AddPermissionsBits(Filename, 0444);
-}
-
-/// getFileSize - Return the size of the specified file in bytes, or -1 if the
-/// file cannot be read or does not exist.
-long long llvm::getFileSize(const std::string &Filename) {
- struct stat StatBuf;
- if (stat(Filename.c_str(), &StatBuf) == -1)
- return -1;
- return StatBuf.st_size;
-}
-
-/// getFileTimestamp - Get the last modified time for the specified file in an
-/// unspecified format. This is useful to allow checking to see if a file was
-/// updated since that last time the timestampt was aquired. If the file does
-/// not exist or there is an error getting the time-stamp, zero is returned.
-unsigned long long llvm::getFileTimestamp(const std::string &Filename) {
- struct stat StatBuf;
- if (stat(Filename.c_str(), &StatBuf) == -1)
- return 0;
- return StatBuf.st_mtime;
-}
-
-/// ReadFileIntoAddressSpace - Attempt to map the specific file into the
-/// address space of the current process for reading. If this succeeds,
-/// return the address of the buffer and the length of the file mapped. On
-/// failure, return null.
-void *llvm::ReadFileIntoAddressSpace(const std::string &Filename,
- unsigned &Length) {
-#ifdef HAVE_MMAP_FILE
- Length = getFileSize(Filename);
- if ((int)Length == -1) return 0;
-
- FDHandle FD(open(Filename.c_str(), O_RDONLY));
- if (FD == -1) return 0;
-
- // If the file has a length of zero, mmap might return a null pointer. In
- // this case, allocate a single byte of memory and return it instead.
- if (Length == 0)
- return malloc(1);
-
- // mmap in the file all at once...
- void *Buffer = (void*)mmap(0, Length, PROT_READ, MAP_PRIVATE, FD, 0);
-
- if (Buffer == (void*)MAP_FAILED)
- return 0;
-
- return Buffer;
-#else
- // FIXME: implement with read/write
- return 0;
-#endif
-}
-
-/// UnmapFileFromAddressSpace - Remove the specified file from the current
-/// address space.
-void llvm::UnmapFileFromAddressSpace(void *Buffer, unsigned Length) {
-#ifdef HAVE_MMAP_FILE
- if (Length)
- munmap((char*)Buffer, Length);
- else
- free(Buffer); // Zero byte files are malloc(1)'s.
-#else
- free(Buffer);
-#endif
-}
-
-//===----------------------------------------------------------------------===//
-// FDHandle class implementation
-//
-
-FDHandle::~FDHandle() throw() {
- if (FD != -1) close(FD);
-}
-
-FDHandle &FDHandle::operator=(int fd) throw() {
- if (FD != -1) close(FD);
- FD = fd;
- return *this;
+int llvm::DiffFilesWithTolerance(const sys::Path &FileA,
+ const sys::Path &FileB,
+ double AbsTol, double RelTol,
+ std::string *Error) {
+ try {
+ // Check for zero length files because some systems croak when you try to
+ // mmap an empty file.
+ size_t A_size = FileA.getSize();
+ size_t B_size = FileB.getSize();
+
+ // If they are both zero sized then they're the same
+ if (A_size == 0 && B_size == 0)
+ return 0;
+ // If only one of them is zero sized then they can't be the same
+ if ((A_size == 0 || B_size == 0))
+ return 1;
+
+ // Now its safe to mmap the files into memory becasue both files
+ // have a non-zero size.
+ sys::MappedFile F1(FileA);
+ sys::MappedFile F2(FileB);
+ F1.map();
+ F2.map();
+
+ // Okay, now that we opened the files, scan them for the first difference.
+ char *File1Start = F1.charBase();
+ char *File2Start = F2.charBase();
+ char *File1End = File1Start+A_size;
+ char *File2End = File2Start+B_size;
+ char *F1P = File1Start;
+ char *F2P = File2Start;
+
+ if (A_size == B_size) {
+ // Are the buffers identical?
+ if (std::memcmp(File1Start, File2Start, A_size) == 0)
+ return 0;
+
+ if (AbsTol == 0 && RelTol == 0)
+ return 1; // Files different!
+ }
+
+ char *OrigFile1Start = File1Start;
+ char *OrigFile2Start = File2Start;
+
+ // If the files need padding, do so now.
+ PadFileIfNeeded(File1Start, File1End, F1P);
+ PadFileIfNeeded(File2Start, File2End, F2P);
+
+ bool CompareFailed = false;
+ while (1) {
+ // Scan for the end of file or next difference.
+ while (F1P < File1End && F2P < File2End && *F1P == *F2P)
+ ++F1P, ++F2P;
+
+ if (F1P >= File1End || F2P >= File2End) break;
+
+ // Okay, we must have found a difference. Backup to the start of the
+ // current number each stream is at so that we can compare from the
+ // beginning.
+ F1P = BackupNumber(F1P, File1Start);
+ F2P = BackupNumber(F2P, File2Start);
+
+ // Now that we are at the start of the numbers, compare them, exiting if
+ // they don't match.
+ if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) {
+ CompareFailed = true;
+ break;
+ }
+ }
+
+ // Okay, we reached the end of file. If both files are at the end, we
+ // succeeded.
+ bool F1AtEnd = F1P >= File1End;
+ bool F2AtEnd = F2P >= File2End;
+ if (!CompareFailed && (!F1AtEnd || !F2AtEnd)) {
+ // Else, we might have run off the end due to a number: backup and retry.
+ if (F1AtEnd && isNumberChar(F1P[-1])) --F1P;
+ if (F2AtEnd && isNumberChar(F2P[-1])) --F2P;
+ F1P = BackupNumber(F1P, File1Start);
+ F2P = BackupNumber(F2P, File2Start);
+
+ // Now that we are at the start of the numbers, compare them, exiting if
+ // they don't match.
+ if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error))
+ CompareFailed = true;
+
+ // If we found the end, we succeeded.
+ if (F1P < File1End || F2P < File2End)
+ CompareFailed = true;
+ }
+
+ if (OrigFile1Start != File1Start)
+ delete[] (File1Start-1); // Back up past null byte
+ if (OrigFile2Start != File2Start)
+ delete[] (File2Start-1); // Back up past null byte
+ return CompareFailed;
+ } catch (const std::string &Msg) {
+ if (Error) *Error = Msg;
+ return 2;
+ }