[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);
- git-merge-changelog and EOL format on Windows,
Eli Zaretskii <=