]> asedeno.scripts.mit.edu Git - git.git/blobdiff - diff.c
Merge branch 'rg/doc-workflow' into maint
[git.git] / diff.c
diff --git a/diff.c b/diff.c
index e03b16c0066181e3a07faaed9db582bc447c4633..cc0cb2b31f3f9b4ff00b12ad1d07671c7228749d 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -273,18 +273,31 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
        ecbdata->blank_at_eof_in_postimage = (at - l2) + 1;
 }
 
-static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len)
+static void emit_line_0(FILE *file, const char *set, const char *reset,
+                       int first, const char *line, int len)
 {
        int has_trailing_newline, has_trailing_carriage_return;
+       int nofirst;
 
-       has_trailing_newline = (len > 0 && line[len-1] == '\n');
-       if (has_trailing_newline)
-               len--;
-       has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
-       if (has_trailing_carriage_return)
-               len--;
+       if (len == 0) {
+               has_trailing_newline = (first == '\n');
+               has_trailing_carriage_return = (!has_trailing_newline &&
+                                               (first == '\r'));
+               nofirst = has_trailing_newline || has_trailing_carriage_return;
+       } else {
+               has_trailing_newline = (len > 0 && line[len-1] == '\n');
+               if (has_trailing_newline)
+                       len--;
+               has_trailing_carriage_return = (len > 0 && line[len-1] == '\r');
+               if (has_trailing_carriage_return)
+                       len--;
+               nofirst = 0;
+       }
 
        fputs(set, file);
+
+       if (!nofirst)
+               fputc(first, file);
        fwrite(line, len, 1, file);
        fputs(reset, file);
        if (has_trailing_carriage_return)
@@ -293,6 +306,12 @@ static void emit_line(FILE *file, const char *set, const char *reset, const char
                fputc('\n', file);
 }
 
+static void emit_line(FILE *file, const char *set, const char *reset,
+                     const char *line, int len)
+{
+       emit_line_0(file, set, reset, line[0], line+1, len-1);
+}
+
 static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len)
 {
        if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) &&
@@ -301,23 +320,25 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
              ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage &&
              ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage))
                return 0;
-       return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule);
+       return ws_blank_line(line, len, ecbdata->ws_rule);
 }
 
-static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len)
+static void emit_add_line(const char *reset,
+                         struct emit_callback *ecbdata,
+                         const char *line, int len)
 {
        const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE);
        const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW);
 
        if (!*ws)
-               emit_line(ecbdata->file, set, reset, line, len);
+               emit_line_0(ecbdata->file, set, reset, '+', line, len);
        else if (new_blank_line_at_eof(ecbdata, line, len))
                /* Blank line at EOF - paint '+' as well */
-               emit_line(ecbdata->file, ws, reset, line, len);
+               emit_line_0(ecbdata->file, ws, reset, '+', line, len);
        else {
                /* Emit just the prefix, then the rest. */
-               emit_line(ecbdata->file, set, reset, line, 1);
-               ws_check_emit(line + 1, len - 1, ecbdata->ws_rule,
+               emit_line_0(ecbdata->file, set, reset, '+', "", 0);
+               ws_check_emit(line, len, ecbdata->ws_rule,
                              ecbdata->file, set, reset, ws);
        }
 }
@@ -364,26 +385,36 @@ static void print_line_count(FILE *file, int count)
        }
 }
 
-static void copy_file_with_prefix(FILE *file,
-                                 int prefix, const char *data, int size,
-                                 const char *set, const char *reset)
+static void emit_rewrite_lines(struct emit_callback *ecb,
+                              int prefix, const char *data, int size)
 {
-       int ch, nl_just_seen = 1;
-       while (0 < size--) {
-               ch = *data++;
-               if (nl_just_seen) {
-                       fputs(set, file);
-                       putc(prefix, file);
+       const char *endp = NULL;
+       static const char *nneof = " No newline at end of file\n";
+       const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD);
+       const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET);
+
+       while (0 < size) {
+               int len;
+
+               endp = memchr(data, '\n', size);
+               len = endp ? (endp - data + 1) : size;
+               if (prefix != '+') {
+                       ecb->lno_in_preimage++;
+                       emit_line_0(ecb->file, old, reset, '-',
+                                   data, len);
+               } else {
+                       ecb->lno_in_postimage++;
+                       emit_add_line(reset, ecb, data, len);
                }
-               if (ch == '\n') {
-                       nl_just_seen = 1;
-                       fputs(reset, file);
-               } else
-                       nl_just_seen = 0;
-               putc(ch, file);
+               size -= len;
+               data += len;
+       }
+       if (!endp) {
+               const char *plain = diff_get_color(ecb->color_diff,
+                                                  DIFF_PLAIN);
+               emit_line_0(ecb->file, plain, reset, '\\',
+                           nneof, strlen(nneof));
        }
-       if (!nl_just_seen)
-               fprintf(file, "%s\n\\ No newline at end of file\n", reset);
 }
 
 static void emit_rewrite_diff(const char *name_a,
@@ -399,13 +430,12 @@ static void emit_rewrite_diff(const char *name_a,
        const char *name_a_tab, *name_b_tab;
        const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO);
        const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO);
-       const char *old = diff_get_color(color_diff, DIFF_FILE_OLD);
-       const char *new = diff_get_color(color_diff, DIFF_FILE_NEW);
        const char *reset = diff_get_color(color_diff, DIFF_RESET);
        static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT;
        const char *a_prefix, *b_prefix;
        const char *data_one, *data_two;
        size_t size_one, size_two;
+       struct emit_callback ecbdata;
 
        if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
                a_prefix = o->b_prefix;
@@ -446,6 +476,22 @@ static void emit_rewrite_diff(const char *name_a,
                size_two = two->size;
        }
 
+       memset(&ecbdata, 0, sizeof(ecbdata));
+       ecbdata.color_diff = color_diff;
+       ecbdata.found_changesp = &o->found_changes;
+       ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a);
+       ecbdata.file = o->file;
+       if (ecbdata.ws_rule & WS_BLANK_AT_EOF) {
+               mmfile_t mf1, mf2;
+               mf1.ptr = (char *)data_one;
+               mf2.ptr = (char *)data_two;
+               mf1.size = size_one;
+               mf2.size = size_two;
+               check_blank_at_eof(&mf1, &mf2, &ecbdata);
+       }
+       ecbdata.lno_in_preimage = 1;
+       ecbdata.lno_in_postimage = 1;
+
        lc_a = count_lines(data_one, size_one);
        lc_b = count_lines(data_two, size_two);
        fprintf(o->file,
@@ -457,9 +503,9 @@ static void emit_rewrite_diff(const char *name_a,
        print_line_count(o->file, lc_b);
        fprintf(o->file, " @@%s\n", reset);
        if (lc_a)
-               copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset);
+               emit_rewrite_lines(&ecbdata, '-', data_one, size_one);
        if (lc_b)
-               copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset);
+               emit_rewrite_lines(&ecbdata, '+', data_two, size_two);
 }
 
 struct diff_words_buffer {
@@ -639,14 +685,18 @@ static void diff_words_show(struct diff_words_data *diff_words)
        diff_words->minus.text.size = diff_words->plus.text.size = 0;
 }
 
+/* In "color-words" mode, show word-diff of words accumulated in the buffer */
+static void diff_words_flush(struct emit_callback *ecbdata)
+{
+       if (ecbdata->diff_words->minus.text.size ||
+           ecbdata->diff_words->plus.text.size)
+               diff_words_show(ecbdata->diff_words);
+}
+
 static void free_diff_words_data(struct emit_callback *ecbdata)
 {
        if (ecbdata->diff_words) {
-               /* flush buffers */
-               if (ecbdata->diff_words->minus.text.size ||
-                               ecbdata->diff_words->plus.text.size)
-                       diff_words_show(ecbdata->diff_words);
-
+               diff_words_flush(ecbdata);
                free (ecbdata->diff_words->minus.text.ptr);
                free (ecbdata->diff_words->minus.orig);
                free (ecbdata->diff_words->plus.text.ptr);
@@ -726,6 +776,8 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
        }
 
        if (line[0] == '@') {
+               if (ecbdata->diff_words)
+                       diff_words_flush(ecbdata);
                len = sane_truncate_line(ecbdata, line, len);
                find_lno(line, ecbdata);
                emit_line(ecbdata->file,
@@ -751,9 +803,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                                          &ecbdata->diff_words->plus);
                        return;
                }
-               if (ecbdata->diff_words->minus.text.size ||
-                   ecbdata->diff_words->plus.text.size)
-                       diff_words_show(ecbdata->diff_words);
+               diff_words_flush(ecbdata);
                line++;
                len--;
                emit_line(ecbdata->file, plain, reset, line, len);
@@ -770,7 +820,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len)
                emit_line(ecbdata->file, color, reset, line, len);
        } else {
                ecbdata->lno_in_postimage++;
-               emit_add_line(reset, ecbdata, line, len);
+               emit_add_line(reset, ecbdata, line + 1, len - 1);
        }
 }
 
@@ -2762,7 +2812,7 @@ static int parse_num(const char **cp_p)
        num = 0;
        scale = 1;
        dot = 0;
-       for(;;) {
+       for (;;) {
                ch = *cp;
                if ( !dot && ch == '.' ) {
                        scale = 1;