ソースを参照

BUG: Wrote correct implementation of cmCopyFile.

Brad King 24 年 前
コミット
373c1663cf
1 ファイル変更40 行追加13 行削除
  1. 40 13
      Source/cmSystemTools.cxx

+ 40 - 13
Source/cmSystemTools.cxx

@@ -657,27 +657,54 @@ bool cmSystemTools::FilesDiffer(const char* source,
 }
 
 
-
+/**
+ * Copy a file named by "source" to the file named by "destination".  This
+ * implementation makes correct use of the C++ standard file streams to
+ * perfectly copy any file with lines of any length (even binary files).
+ */
 void cmSystemTools::cmCopyFile(const char* source,
-                             const char* destination)
+                               const char* destination)
 {
-  std::ifstream fin(source);
-  char buff[4096];
-  std::ofstream fout(destination);
-  if(!fout )
+  // Buffer length is only for block size.  Any file would still be copied
+  // correctly if this were as small as 2.
+  const int buffer_length = 4096;
+  char buffer[buffer_length];
+  std::ifstream fin(source,
+                    std::ios::binary | std::ios::in);
+  if(!fin)
     {
-    cmSystemTools::Error("CopyFile failed to open input file", source);
+    cmSystemTools::Error("CopyFile failed to open input file \"",
+                         source, "\"");
     }
-  if(!fin)
+  std::ofstream fout(destination,
+                     std::ios::binary | std::ios::out | std::ios::trunc);
+  if(!fout)
     {
-    cmSystemTools::Error("CopyFile failed to open output file", destination);
+    cmSystemTools::Error("CopyFile failed to open output file \"",
+                         destination, "\"");
     }
-  while(fin)
+  while(fin.getline(buffer, buffer_length, '\n') || fin.gcount())
     {
-    fin.getline(buff, 4096);
-    if(fin)
+    std::streamsize count = fin.gcount();
+    if(fin.eof())
+      {
+      // Final line, but with no newline.
+      fout.write(buffer, count);
+      }
+    else if(fin.fail())
+      {
+      // Part of a line longer than our buffer, clear the fail bit of
+      // the stream so that we can continue.
+      fin.clear(fin.rdstate() & ~std::ios::failbit);
+      fout.write(buffer, count);
+      }
+    else
       {
-      fout << buff << "\n";
+      // Line on which a newline was encountered.  It was read from
+      // the stream, but not stored.
+      --count;
+      fout.write(buffer, count);
+      fout << '\n';
       }
     }
 }