>From 6f9c561a1ef3b170011908727a6570bf4e210279 Mon Sep 17 00:00:00 2001 From: Paul Eggert 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