On further thought, I came up with a patch that should be portable without overly complicating the code or hurting efficiency, so I installed it (attached). Please give it a try on your platform.

I am still leery about changing the GNU coding standards, though. In general we shouldn't ask developers to jump through these sorts of hoops for platforms so far from the typical GNU environment.
>From 6f9c561a1ef3b170011908727a6570bf4e210279 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Sat, 27 Aug 2016 14:59:13 -0700
Subject: [PATCH] diff: port line numbers to mingw64

Problem reported by Peter Rosin (Bug#24311).
* src/system.h (printint, pI): New typedef and macro.
All uses of 'long int' and "%l" in printf format replaced by
'printint' and "%"pI respectively.
* src/ifdef.c (do_printf_spec): Don't assume pI is length 1.
---
 NEWS          |  4 ++++
 src/context.c | 12 ++++++------
 src/diff.h    |  2 +-
 src/diff3.c   | 35 +++++++++++++++++------------------
 src/ed.c      |  8 +++++---
 src/ifdef.c   | 15 ++++++++-------
 src/sdiff.c   | 16 ++++++++--------
 src/side.c    | 12 ++++++------
 src/system.h  | 24 ++++++++++++++++++++----
 src/util.c    | 22 +++++++++++-----------
 10 files changed, 86 insertions(+), 64 deletions(-)

diff --git a/NEWS b/NEWS
index accdf88..473332e 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ GNU diffutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  diff no longer mishandles line numbers exceeding 2**31 on Mingw-w64.
+
 
 * Noteworthy changes in release 3.5 (2016-08-20) [stable]
 
diff --git a/src/context.c b/src/context.c
index 1a92a60..1a663ba 100644
--- a/src/context.c
+++ b/src/context.c
@@ -126,7 +126,7 @@ print_context_script (struct change *script, bool unidiff)
 static void
 print_context_number_range (struct file_data const *file, lin a, lin b)
 {
-  long int trans_a, trans_b;
+  printint trans_a, trans_b;
   translate_range (file, a, b, &trans_a, &trans_b);
 
   /* We can have B <= A in the case of a range of no lines.
@@ -139,9 +139,9 @@ print_context_number_range (struct file_data const *file, lin a, lin b)
      specification.  */
 
   if (trans_b <= trans_a)
-    fprintf (outfile, "%ld", trans_b);
+    fprintf (outfile, "%"pI"d", trans_b);
   else
-    fprintf (outfile, "%ld,%ld", trans_a, trans_b);
+    fprintf (outfile, "%"pI"d,%"pI"d", trans_a, trans_b);
 }
 
 /* Print FUNCTION in a context header.  */
@@ -299,7 +299,7 @@ pr_context_hunk (struct change *hunk)
 static void
 print_unidiff_number_range (struct file_data const *file, lin a, lin b)
 {
-  long int trans_a, trans_b;
+  printint trans_a, trans_b;
   translate_range (file, a, b, &trans_a, &trans_b);
 
   /* We can have B < A in the case of a range of no lines.
@@ -307,9 +307,9 @@ print_unidiff_number_range (struct file_data const *file, lin a, lin b)
      which is B.  It would be more logical to print A, but
      'patch' expects B in order to detect diffs against empty files.  */
   if (trans_b <= trans_a)
-    fprintf (outfile, trans_b < trans_a ? "%ld,0" : "%ld", trans_b);
+    fprintf (outfile, trans_b < trans_a ? "%"pI"d,0" : "%"pI"d", trans_b);
   else
-    fprintf (outfile, "%ld,%ld", trans_a, trans_b - trans_a + 1);
+    fprintf (outfile, "%"pI"d,%"pI"d", trans_a, trans_b - trans_a + 1);
 }
 
 /* Print a portion of an edit script in unidiff format.
diff --git a/src/diff.h b/src/diff.h
index 0983e7c..6eda1e6 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -406,7 +406,7 @@ extern void print_script (struct change *, struct change * (*) (struct change *)
                           void (*) (struct change *));
 extern void setup_output (char const *, char const *, bool);
 extern void translate_range (struct file_data const *, lin, lin,
-                             long int *, long int *);
+                             printint *, printint *);
 
 enum color_context
 {
diff --git a/src/diff3.c b/src/diff3.c
index b80aeb3..b2de4b6 100644
--- a/src/diff3.c
+++ b/src/diff3.c
@@ -1428,20 +1428,20 @@ output_diff3 (FILE *outputfile, struct diff3_block *diff,
 	  int realfile = mapping[i];
 	  lin lowt = D_LOWLINE (ptr, realfile);
 	  lin hight = D_HIGHLINE (ptr, realfile);
-	  long int llowt = lowt;
-	  long int lhight = hight;
+	  printint llowt = lowt;
+	  printint lhight = hight;
 
 	  fprintf (outputfile, "%d:", i + 1);
 	  switch (lowt - hight)
 	    {
 	    case 1:
-	      fprintf (outputfile, "%lda\n", llowt - 1);
+	      fprintf (outputfile, "%"pI"da\n", llowt - 1);
 	      break;
 	    case 0:
-	      fprintf (outputfile, "%ldc\n", llowt);
+	      fprintf (outputfile, "%"pI"dc\n", llowt);
 	      break;
 	    default:
-	      fprintf (outputfile, "%ld,%ldc\n", llowt, lhight);
+	      fprintf (outputfile, "%"pI"d,%"pI"dc\n", llowt, lhight);
 	      break;
 	    }
 
@@ -1495,19 +1495,18 @@ dotlines (FILE *outputfile, struct diff3_block *b, int filenum)
 
 /* Output to OUTPUTFILE a '.' line.  If LEADING_DOT is true, also
    output a command that removes initial '.'s starting with line START
-   and continuing for NUM lines.  (START is long int, not lin, for
-   convenience with printf %ld formats.)  */
+   and continuing for NUM lines.  */
 
 static void
-undotlines (FILE *outputfile, bool leading_dot, long int start, lin num)
+undotlines (FILE *outputfile, bool leading_dot, printint start, printint num)
 {
   fputs (".\n", outputfile);
   if (leading_dot)
     {
       if (num == 1)
-	fprintf (outputfile, "%lds/^\\.//\n", start);
+	fprintf (outputfile, "%"pI"ds/^\\.//\n", start);
       else
-	fprintf (outputfile, "%ld,%lds/^\\.//\n", start, start + num - 1);
+	fprintf (outputfile, "%"pI"d,%"pI"ds/^\\.//\n", start, start + num - 1);
     }
 }
 
@@ -1548,7 +1547,7 @@ output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
 	   ? DIFF_ALL
 	   : DIFF_1ST + rev_mapping[b->correspond - DIFF_1ST]);
 
-      long int low0, high0;
+      printint low0, high0;
 
       /* If we aren't supposed to do this output block, skip it.  */
       switch (type)
@@ -1569,7 +1568,7 @@ output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
 
 	  /* Mark end of conflict.  */
 
-	  fprintf (outputfile, "%lda\n", high0);
+	  fprintf (outputfile, "%"pI"da\n", high0);
 	  leading_dot = false;
 	  if (type == DIFF_ALL)
 	    {
@@ -1591,7 +1590,7 @@ output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
 
 	  /* Mark start of conflict.  */
 
-	  fprintf (outputfile, "%lda\n<<<<<<< %s\n", low0 - 1,
+	  fprintf (outputfile, "%"pI"da\n<<<<<<< %s\n", low0 - 1,
 		   type == DIFF_ALL ? file0 : file1);
 	  leading_dot = false;
 	  if (type == DIFF_2ND)
@@ -1607,9 +1606,9 @@ output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
 	/* Write out a delete */
 	{
 	  if (low0 == high0)
-	    fprintf (outputfile, "%ldd\n", low0);
+	    fprintf (outputfile, "%"pI"dd\n", low0);
 	  else
-	    fprintf (outputfile, "%ld,%ldd\n", low0, high0);
+	    fprintf (outputfile, "%"pI"d,%"pI"dd\n", low0, high0);
 	}
       else
 	/* Write out an add or change */
@@ -1617,13 +1616,13 @@ output_diff3_edscript (FILE *outputfile, struct diff3_block *diff,
 	  switch (high0 - low0)
 	    {
 	    case -1:
-	      fprintf (outputfile, "%lda\n", high0);
+	      fprintf (outputfile, "%"pI"da\n", high0);
 	      break;
 	    case 0:
-	      fprintf (outputfile, "%ldc\n", high0);
+	      fprintf (outputfile, "%"pI"dc\n", high0);
 	      break;
 	    default:
-	      fprintf (outputfile, "%ld,%ldc\n", low0, high0);
+	      fprintf (outputfile, "%"pI"d,%"pI"dc\n", low0, high0);
 	      break;
 	    }
 
diff --git a/src/ed.c b/src/ed.c
index 1fae2b8..6c9192c 100644
--- a/src/ed.c
+++ b/src/ed.c
@@ -144,7 +144,7 @@ static void
 print_rcs_hunk (struct change *hunk)
 {
   lin i, f0, l0, f1, l1;
-  long int tf0, tl0, tf1, tl1;
+  printint tf0, tl0, tf1, tl1;
 
   /* Determine range of line numbers involved in each file.  */
   enum changes changes = analyze_hunk (hunk, &f0, &l0, &f1, &l1);
@@ -159,14 +159,16 @@ print_rcs_hunk (struct change *hunk)
     {
       /* For deletion, print just the starting line number from file 0
 	 and the number of lines deleted.  */
-      fprintf (outfile, "d%ld %ld\n", tf0, tf0 <= tl0 ? tl0 - tf0 + 1 : 1);
+      fprintf (outfile, "d%"pI"d %"pI"d\n", tf0,
+	       tf0 <= tl0 ? tl0 - tf0 + 1 : 1);
     }
 
   if (changes & NEW)
     {
       /* Take last-line-number from file 0 and # lines from file 1.  */
       translate_range (&files[1], f1, l1, &tf1, &tl1);
-      fprintf (outfile, "a%ld %ld\n", tl0, tf1 <= tl1 ? tl1 - tf1 + 1 : 1);
+      fprintf (outfile, "a%"pI"d %"pI"d\n", tl0,
+	       tf1 <= tl1 ? tl1 - tf1 + 1 : 1);
 
       /* Print the inserted lines.  */
       for (i = f1; i <= l1; i++)
diff --git a/src/ifdef.c b/src/ifdef.c
index b8b084f..d67eb5b 100644
--- a/src/ifdef.c
+++ b/src/ifdef.c
@@ -357,21 +357,22 @@ do_printf_spec (FILE *out, char const *spec,
 
 	if (out)
 	  {
-	    /* For example, if the spec is "%3xn", use the printf
+	    /* For example, if the spec is "%3xn" and pI is "l", use the printf
 	       format spec "%3lx".  Here the spec prefix is "%3".  */
-	    long int long_value = value;
+	    printint print_value = value;
 	    size_t spec_prefix_len = f - spec - 2;
+	    size_t pI_len = sizeof pI - 1;
 #if HAVE_C_VARARRAYS
-	    char format[spec_prefix_len + 3];
+	    char format[spec_prefix_len + pI_len + 2];
 #else
-	    char *format = xmalloc (spec_prefix_len + 3);
+	    char *format = xmalloc (spec_prefix_len + pI_len + 2);
 #endif
-	    char *p = format + spec_prefix_len;
+	    char *p = format + spec_prefix_len + pI_len;
 	    memcpy (format, spec, spec_prefix_len);
-	    *p++ = 'l';
+	    memcpy (format + spec_prefix_len, pI, pI_len);
 	    *p++ = c;
 	    *p = '\0';
-	    fprintf (out, format, long_value);
+	    fprintf (out, format, print_value);
 #if ! HAVE_C_VARARRAYS
 	    free (format);
 #endif
diff --git a/src/sdiff.c b/src/sdiff.c
index 22d6e5b..d900779 100644
--- a/src/sdiff.c
+++ b/src/sdiff.c
@@ -967,12 +967,12 @@ edit (struct line_filter *left, char const *lname, lin lline, lin llen,
 	      case 'd':
 		if (llen)
 		  {
+		    printint l1 = lline;
+		    printint l2 = lline + llen - 1;
 		    if (llen == 1)
-		      fprintf (tmp, "--- %s %ld\n", lname, (long int) lline);
+		      fprintf (tmp, "--- %s %"pI"d\n", lname, l1);
 		    else
-		      fprintf (tmp, "--- %s %ld,%ld\n", lname,
-			       (long int) lline,
-			       (long int) (lline + llen - 1));
+		      fprintf (tmp, "--- %s %"pI"d,%"pI"d\n", lname, l1, l2);
 		  }
 		/* Fall through.  */
 	      case '1': case 'b': case 'l':
@@ -989,12 +989,12 @@ edit (struct line_filter *left, char const *lname, lin lline, lin llen,
 	      case 'd':
 		if (rlen)
 		  {
+		    printint l1 = rline;
+		    printint l2 = rline + rlen - 1;
 		    if (rlen == 1)
-		      fprintf (tmp, "+++ %s %ld\n", rname, (long int) rline);
+		      fprintf (tmp, "+++ %s %"pI"d\n", rname, l1);
 		    else
-		      fprintf (tmp, "+++ %s %ld,%ld\n", rname,
-			       (long int) rline,
-			       (long int) (rline + rlen - 1));
+		      fprintf (tmp, "+++ %s %"pI"d,%"pI"d\n", rname, l1, l2);
 		  }
 		/* Fall through.  */
 	      case '2': case 'b': case 'r':
diff --git a/src/side.c b/src/side.c
index 2276385..40356c9 100644
--- a/src/side.c
+++ b/src/side.c
@@ -260,9 +260,9 @@ print_sdiff_common_lines (lin limit0, lin limit1)
     {
       if (sdiff_merge_assist)
 	{
-	  long int len0 = limit0 - i0;
-	  long int len1 = limit1 - i1;
-	  fprintf (outfile, "i%ld,%ld\n", len0, len1);
+	  printint len0 = limit0 - i0;
+	  printint len1 = limit1 - i1;
+	  fprintf (outfile, "i%"pI"d,%"pI"d\n", len0, len1);
 	}
 
       if (!left_column)
@@ -302,9 +302,9 @@ print_sdiff_hunk (struct change *hunk)
 
   if (sdiff_merge_assist)
     {
-      long int len0 = last0 - first0 + 1;
-      long int len1 = last1 - first1 + 1;
-      fprintf (outfile, "c%ld,%ld\n", len0, len1);
+      printint len0 = last0 - first0 + 1;
+      printint len1 = last1 - first1 + 1;
+      fprintf (outfile, "c%"pI"d,%"pI"d\n", len0, len1);
     }
 
   /* Print "xxx  |  xxx " lines.  */
diff --git a/src/system.h b/src/system.h
index be1c0bd..481d3a0 100644
--- a/src/system.h
+++ b/src/system.h
@@ -127,14 +127,30 @@ int strcasecmp (char const *, char const *);
 # define word size_t
 #endif
 
-/* The integer type of a line number.  Since files are read into main
-   memory, ptrdiff_t should be wide enough.  */
+/* The signed integer type of a line number.  Since files are read
+   into main memory, ptrdiff_t should be wide enough.  */
 
 typedef ptrdiff_t lin;
 #define LIN_MAX PTRDIFF_MAX
+
+/* The signed integer type for printing line numbers, and its printf
+   length modifier.  Prefer 'long int' if it suffices, to cater to C
+   implementations that lack support for "ll".  The natural
+   C99-or-later implementation with ptrdiff_t and "t" is less portable
+   in practice.  */
+
+#if LIN_MAX <= LONG_MAX
+typedef long int printint;
+# define pI "l"
+#else
+typedef long long int printint;
+# define pI "ll"
+#endif
+
 verify (TYPE_SIGNED (lin));
-verify (sizeof (ptrdiff_t) <= sizeof (lin));
-verify (sizeof (lin) <= sizeof (long int));
+verify (TYPE_SIGNED (printint));
+verify (LIN_MAX == TYPE_MAXIMUM (lin));
+verify (LIN_MAX <= TYPE_MAXIMUM (printint));
 
 /* Limit so that 2 * CONTEXT + 1 does not overflow.  */
 
diff --git a/src/util.c b/src/util.c
index 76872cb..bef2bff 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1401,13 +1401,13 @@ translate_line_number (struct file_data const *file, lin i)
 }
 
 /* Translate a line number range.  This is always done for printing,
-   so for convenience translate to long int rather than lin, so that the
-   caller can use printf with "%ld" without casting.  */
+   so for convenience translate to printint rather than lin, so that the
+   caller can use printf with "%"pI"d" without casting.  */
 
 void
 translate_range (struct file_data const *file,
 		 lin a, lin b,
-		 long int *aptr, long int *bptr)
+		 printint *aptr, printint *bptr)
 {
   *aptr = translate_line_number (file, a - 1) + 1;
   *bptr = translate_line_number (file, b + 1) - 1;
@@ -1422,16 +1422,16 @@ translate_range (struct file_data const *file,
 void
 print_number_range (char sepchar, struct file_data *file, lin a, lin b)
 {
-  long int trans_a, trans_b;
+  printint trans_a, trans_b;
   translate_range (file, a, b, &trans_a, &trans_b);
 
   /* Note: we can have B < A in the case of a range of no lines.
      In this case, we should print the line number before the range,
      which is B.  */
   if (trans_b > trans_a)
-    fprintf (outfile, "%ld%c%ld", trans_a, sepchar, trans_b);
+    fprintf (outfile, "%"pI"d%c%"pI"d", trans_a, sepchar, trans_b);
   else
-    fprintf (outfile, "%ld", trans_b);
+    fprintf (outfile, "%"pI"d", trans_b);
 }
 
 /* Look at a hunk of edit script and report the range of lines in each file
@@ -1565,11 +1565,11 @@ debug_script (struct change *sp)
 
   for (; sp; sp = sp->link)
     {
-      long int line0 = sp->line0;
-      long int line1 = sp->line1;
-      long int deleted = sp->deleted;
-      long int inserted = sp->inserted;
-      fprintf (stderr, "%3ld %3ld delete %ld insert %ld\n",
+      printint line0 = sp->line0;
+      printint line1 = sp->line1;
+      printint deleted = sp->deleted;
+      printint inserted = sp->inserted;
+      fprintf (stderr, "%3"pI"d %3"pI"d delete %"pI"d insert %"pI"d\n",
 	       line0, line1, deleted, inserted);
     }
 
-- 
2.7.4

Reply via email to