bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

git-merge-changelog and EOL format on Windows


From: Eli Zaretskii
Subject: git-merge-changelog and EOL format on Windows
Date: Sat, 18 Jan 2014 12:36:40 +0200

git-merge-changelog does its I/O in text mode.  This is explained in
the sources for the input direction:

  /* Read a ChangeLog file into memory.
     Return the contents in *RESULT.  */
  static void
  read_changelog_file (const char *filename, struct changelog_file *result)
  {
    /* Read the file in text mode, otherwise it's hard to recognize empty
       lines.  */

But no similar explanation is provided for the output.

The result is that, when the program runs on MS-Windows, the merged
ChangeLog file is always output with the DOS-style CR-LF EOLs.  This
gets in the way when git's core.autocrlf config option is set to
false, because almost all projects have ChangeLog files in Unix
LF-only EOL format, and the merged file will have all of its lines
modified.  Oops!

The changes below make git-merge-changelog on Windows attempt to
preserve the EOL format of the original file.

2014-01-18  Eli Zaretskii  <address@hidden>

        Preserve the EOL format of the original ChangeLog file.
        * git-merge-changelog.c (detect_eol): New function.
        (main): Use it to detect the EOL format of the destination file
        (%A).  If %A does not have DOS CR-LF EOL format, write the output
        in binary mode.

--- gllib/git-merge-changelog.c~        2013-01-24 07:30:17.000000000 +0200
+++ gllib/git-merge-changelog.c 2014-01-18 11:32:16.140625000 +0200
@@ -279,6 +279,48 @@
   return similarity;
 }
 
+/* Read the initial block of a ChangeLog file, and return true if it
+   uses the DOS/Windows CR-LF end-of-line format, false otherwise.  */
+static bool
+detect_eol (const char *destfn, const char *ancestorfn)
+{
+#ifdef __MINGW32__
+  /* ChangeLog files have relatively short lines, so we don't need to
+     read too much stuff, or worry about too long lines.  */
+  char buf[256];
+  FILE *f = fopen (destfn, "rb");
+  bool result = false; /* default to Unix-style EOLs */
+  size_t nread;
+
+  /* If the destination doesn't exist, inherit the EOL format from the
+     ancestor.  */
+  if (!f)
+    f = fopen (ancestorfn, "rb");
+  if (f && (nread = fread (buf, 1, sizeof (buf) - 1, f)) > 0)
+    {
+      char *p;
+
+      buf[nread] = '\0';
+      /* We assume consistent EOL format throughout the file, so it's
+        enough to examine the first end-of-line.  */
+      p = strchr (buf, '\n');
+
+      if (p > buf)
+       {
+         if (p[-1] == '\r')
+           result = true;
+       }
+    }
+
+  if (f)
+    fclose (f);
+
+  return result;
+#else  /* !__MINGW32__ */
+  return false;
+#endif
+}
+
 /* This structure represents an entire ChangeLog file, after it was read
    into memory.  */
 struct changelog_file
@@ -1079,6 +1121,7 @@
     gl_list_node_t *result_entries_pointers; /* array of pointers into 
result_entries */
     gl_list_t /* <struct entry *> */ result_entries;
     gl_list_t /* <struct conflict *> */ result_conflicts;
+    bool crlf; /* if true, A-FILE-NAME has DOS CR-LF EOL format */
 
     ancestor_file_name = argv[optind];
     destination_file_name = argv[optind + 1];
@@ -1186,6 +1229,10 @@
         modified_file_name = other_file_name;
       }
 
+    /* We want to preserve the EOL format of the destination file,
+       which is the ChangeLog file in the current branch.  */
+    crlf = detect_eol (destination_file_name, ancestor_file_name);
+
     /* Read the three files into memory.  */
     read_changelog_file (ancestor_file_name, &ancestor_file);
     read_changelog_file (mainstream_file_name, &mainstream_file);
@@ -1648,7 +1695,7 @@
 
     /* Output the result.  */
     {
-      FILE *fp = fopen (destination_file_name, "w");
+      FILE *fp = fopen (destination_file_name, crlf ? "w" : "wb");
       if (fp == NULL)
         {
           fprintf (stderr, "could not write file '%s'\n", 
destination_file_name);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]