archive: initialize archivers earlier
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index c5b5e7ac41bf17b16249ce52726fe87b732d71e5..96833c8e81b5d6a7babb523c7ceec0e22ccdab33 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -626,42 +626,54 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
 }
 
 static void emit_line_0(struct diff_options *o,
-                       const char *set, unsigned reverse, const char *reset,
+                       const char *set_sign, const char *set, unsigned reverse, const char *reset,
                        int first, const char *line, int len)
 {
        int has_trailing_newline, has_trailing_carriage_return;
-       int nofirst;
+       int needs_reset = 0; /* at the end of the line */
        FILE *file = o->file;
 
-       if (first)
-               fputs(diff_line_prefix(o), file);
-       else if (!len)
-               return;
+       fputs(diff_line_prefix(o), file);
 
-       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;
+       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 && !first)
+               goto end_of_line;
+
+       if (reverse && want_color(o->use_color)) {
+               fputs(GIT_COLOR_REVERSE, file);
+               needs_reset = 1;
+       }
+
+       if (set_sign) {
+               fputs(set_sign, file);
+               needs_reset = 1;
        }
 
-       if (len || !nofirst) {
-               if (reverse && want_color(o->use_color))
-                       fputs(GIT_COLOR_REVERSE, file);
+       if (first)
+               fputc(first, file);
+
+       if (!len)
+               goto end_of_line;
+
+       if (set) {
+               if (set_sign && set != set_sign)
+                       fputs(reset, file);
                fputs(set, file);
-               if (first && !nofirst)
-                       fputc(first, file);
-               fwrite(line, len, 1, file);
-               fputs(reset, file);
+               needs_reset = 1;
        }
+       fwrite(line, len, 1, file);
+       needs_reset = 1; /* 'line' may contain color codes. */
+
+end_of_line:
+       if (needs_reset)
+               fputs(reset, file);
        if (has_trailing_carriage_return)
                fputc('\r', file);
        if (has_trailing_newline)
@@ -671,7 +683,7 @@ static void emit_line_0(struct diff_options *o,
 static void emit_line(struct diff_options *o, const char *set, const char *reset,
                      const char *line, int len)
 {
-       emit_line_0(o, set, 0, reset, line[0], line+1, len-1);
+       emit_line_0(o, set, NULL, 0, reset, 0, line, len);
 }
 
 enum diff_symbol {
@@ -766,7 +778,6 @@ struct moved_entry {
        struct hashmap_entry ent;
        const struct emitted_diff_symbol *es;
        struct moved_entry *next_line;
-       struct ws_delta *wsd;
 };
 
 /**
@@ -783,6 +794,17 @@ struct ws_delta {
 };
 #define WS_DELTA_INIT { NULL, 0 }
 
+struct moved_block {
+       struct moved_entry *match;
+       struct ws_delta wsd;
+};
+
+static void moved_block_clear(struct moved_block *b)
+{
+       FREE_AND_NULL(b->wsd.string);
+       b->match = NULL;
+}
+
 static int compute_ws_delta(const struct emitted_diff_symbol *a,
                             const struct emitted_diff_symbol *b,
                             struct ws_delta *out)
@@ -791,16 +813,19 @@ static int compute_ws_delta(const struct emitted_diff_symbol *a,
        const struct emitted_diff_symbol *shorter = a->len > b->len ? b : a;
        int d = longer->len - shorter->len;
 
+       if (strncmp(longer->line + d, shorter->line, shorter->len))
+               return 0;
+
        out->string = xmemdupz(longer->line, d);
        out->current_longer = (a == longer);
 
-       return !strncmp(longer->line + d, shorter->line, shorter->len);
+       return 1;
 }
 
 static int cmp_in_block_with_wsd(const struct diff_options *o,
                                 const struct moved_entry *cur,
                                 const struct moved_entry *match,
-                                struct moved_entry *pmb,
+                                struct moved_block *pmb,
                                 int n)
 {
        struct emitted_diff_symbol *l = &o->emitted_symbols->buf[n];
@@ -820,16 +845,15 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
        if (strcmp(a, b))
                return 1;
 
-       if (!pmb->wsd)
+       if (!pmb->wsd.string)
                /*
-                * No white space delta was carried forward? This can happen
-                * when we exit early in this function and do not carry
-                * forward ws.
+                * The white space delta is not active? This can happen
+                * when we exit early in this function.
                 */
                return 1;
 
        /*
-        * The indent changes of the block are known and carried forward in
+        * The indent changes of the block are known and stored in
         * pmb->wsd; however we need to check if the indent changes of the
         * current line are still the same as before.
         *
@@ -837,8 +861,8 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
         * one of them for the white spaces, depending which was longer.
         */
 
-       wslen = strlen(pmb->wsd->string);
-       if (pmb->wsd->current_longer) {
+       wslen = strlen(pmb->wsd.string);
+       if (pmb->wsd.current_longer) {
                c += wslen;
                cl -= wslen;
        } else {
@@ -846,7 +870,7 @@ static int cmp_in_block_with_wsd(const struct diff_options *o,
                al -= wslen;
        }
 
-       if (strcmp(a, c))
+       if (al != cl || memcmp(a, c, al))
                return 1;
 
        return 0;
@@ -888,7 +912,6 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
        ret->ent.hash = xdiff_hash_string(l->line, l->len, flags);
        ret->es = l;
        ret->next_line = NULL;
-       ret->wsd = NULL;
 
        return ret;
 }
@@ -928,18 +951,18 @@ static void add_lines_to_move_detection(struct diff_options *o,
 static void pmb_advance_or_null(struct diff_options *o,
                                struct moved_entry *match,
                                struct hashmap *hm,
-                               struct moved_entry **pmb,
+                               struct moved_block *pmb,
                                int pmb_nr)
 {
        int i;
        for (i = 0; i < pmb_nr; i++) {
-               struct moved_entry *prev = pmb[i];
+               struct moved_entry *prev = pmb[i].match;
                struct moved_entry *cur = (prev && prev->next_line) ?
                                prev->next_line : NULL;
                if (cur && !hm->cmpfn(o, cur, match, NULL)) {
-                       pmb[i] = cur;
+                       pmb[i].match = cur;
                } else {
-                       pmb[i] = NULL;
+                       pmb[i].match = NULL;
                }
        }
 }
@@ -947,7 +970,7 @@ static void pmb_advance_or_null(struct diff_options *o,
 static void pmb_advance_or_null_multi_match(struct diff_options *o,
                                            struct moved_entry *match,
                                            struct hashmap *hm,
-                                           struct moved_entry **pmb,
+                                           struct moved_block *pmb,
                                            int pmb_nr, int n)
 {
        int i;
@@ -955,48 +978,47 @@ static void pmb_advance_or_null_multi_match(struct diff_options *o,
 
        for (; match; match = hashmap_get_next(hm, match)) {
                for (i = 0; i < pmb_nr; i++) {
-                       struct moved_entry *prev = pmb[i];
+                       struct moved_entry *prev = pmb[i].match;
                        struct moved_entry *cur = (prev && prev->next_line) ?
                                        prev->next_line : NULL;
                        if (!cur)
                                continue;
-                       if (!cmp_in_block_with_wsd(o, cur, match, pmb[i], n))
+                       if (!cmp_in_block_with_wsd(o, cur, match, &pmb[i], n))
                                got_match[i] |= 1;
                }
        }
 
        for (i = 0; i < pmb_nr; i++) {
                if (got_match[i]) {
-                       /* Carry the white space delta forward */
-                       pmb[i]->next_line->wsd = pmb[i]->wsd;
-                       pmb[i] = pmb[i]->next_line;
-               } else
-                       pmb[i] = NULL;
+                       /* Advance to the next line */
+                       pmb[i].match = pmb[i].match->next_line;
+               } else {
+                       moved_block_clear(&pmb[i]);
+               }
        }
+
+       free(got_match);
 }
 
-static int shrink_potential_moved_blocks(struct moved_entry **pmb,
+static int shrink_potential_moved_blocks(struct moved_block *pmb,
                                         int pmb_nr)
 {
        int lp, rp;
 
        /* Shrink the set of potential block to the remaining running */
        for (lp = 0, rp = pmb_nr - 1; lp <= rp;) {
-               while (lp < pmb_nr && pmb[lp])
+               while (lp < pmb_nr && pmb[lp].match)
                        lp++;
                /* lp points at the first NULL now */
 
-               while (rp > -1 && !pmb[rp])
+               while (rp > -1 && !pmb[rp].match)
                        rp--;
                /* rp points at the last non-NULL */
 
                if (lp < pmb_nr && rp > -1 && lp < rp) {
                        pmb[lp] = pmb[rp];
-                       if (pmb[rp]->wsd) {
-                               free(pmb[rp]->wsd->string);
-                               FREE_AND_NULL(pmb[rp]->wsd);
-                       }
-                       pmb[rp] = NULL;
+                       pmb[rp].match = NULL;
+                       pmb[rp].wsd.string = NULL;
                        rp--;
                        lp++;
                }
@@ -1043,7 +1065,7 @@ static void mark_color_as_moved(struct diff_options *o,
                                struct hashmap *add_lines,
                                struct hashmap *del_lines)
 {
-       struct moved_entry **pmb = NULL; /* potentially moved blocks */
+       struct moved_block *pmb = NULL; /* potentially moved blocks */
        int pmb_nr = 0, pmb_alloc = 0;
        int n, flipped_block = 1, block_length = 0;
 
@@ -1072,7 +1094,11 @@ static void mark_color_as_moved(struct diff_options *o,
                }
 
                if (!match) {
+                       int i;
+
                        adjust_last_block(o, n, block_length);
+                       for(i = 0; i < pmb_nr; i++)
+                               moved_block_clear(&pmb[i]);
                        pmb_nr = 0;
                        block_length = 0;
                        continue;
@@ -1100,14 +1126,12 @@ static void mark_color_as_moved(struct diff_options *o,
                                ALLOC_GROW(pmb, pmb_nr + 1, pmb_alloc);
                                if (o->color_moved_ws_handling &
                                    COLOR_MOVED_WS_ALLOW_INDENTATION_CHANGE) {
-                                       struct ws_delta *wsd = xmalloc(sizeof(*match->wsd));
-                                       if (compute_ws_delta(l, match->es, wsd)) {
-                                               match->wsd = wsd;
-                                               pmb[pmb_nr++] = match;
-                                       } else
-                                               free(wsd);
+                                       if (compute_ws_delta(l, match->es,
+                                                            &pmb[pmb_nr].wsd))
+                                               pmb[pmb_nr++].match = match;
                                } else {
-                                       pmb[pmb_nr++] = match;
+                                       pmb[pmb_nr].wsd.string = NULL;
+                                       pmb[pmb_nr++].match = match;
                                }
                        }
 
@@ -1124,6 +1148,8 @@ static void mark_color_as_moved(struct diff_options *o,
        }
        adjust_last_block(o, n, block_length);
 
+       for(n = 0; n < pmb_nr; n++)
+               moved_block_clear(&pmb[n]);
        free(pmb);
 }
 
@@ -1189,9 +1215,9 @@ static void dim_moved_lines(struct diff_options *o)
 }
 
 static void emit_line_ws_markup(struct diff_options *o,
-                               const char *set, const char *reset,
-                               const char *line, int len,
-                               const char *set_sign, char sign,
+                               const char *set_sign, const char *set,
+                               const char *reset,
+                               char sign, const char *line, int len,
                                unsigned ws_rule, int blank_at_eof)
 {
        const char *ws = NULL;
@@ -1203,18 +1229,15 @@ static void emit_line_ws_markup(struct diff_options *o,
        }
 
        if (!ws && !set_sign)
-               emit_line_0(o, set, 0, reset, sign, line, len);
+               emit_line_0(o, set, NULL, 0, reset, sign, line, len);
        else if (!ws) {
-               /* Emit just the prefix, then the rest. */
-               emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
-                           sign, "", 0);
-               emit_line_0(o, set, 0, reset, 0, line, len);
+               emit_line_0(o, set_sign, set, !!set_sign, reset, sign, line, len);
        } else if (blank_at_eof)
                /* Blank line at EOF - paint '+' as well */
-               emit_line_0(o, ws, 0, reset, sign, line, len);
+               emit_line_0(o, ws, NULL, 0, reset, sign, line, len);
        else {
                /* Emit just the prefix, then the rest. */
-               emit_line_0(o, set_sign ? set_sign : set, !!set_sign, reset,
+               emit_line_0(o, set_sign ? set_sign : set, NULL, !!set_sign, reset,
                            sign, "", 0);
                ws_check_emit(line, len, ws_rule,
                              o->file, set, reset, ws);
@@ -1238,7 +1261,7 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
                context = diff_get_color_opt(o, DIFF_CONTEXT);
                reset = diff_get_color_opt(o, DIFF_RESET);
                putc('\n', o->file);
-               emit_line_0(o, context, 0, reset, '\\',
+               emit_line_0(o, context, NULL, 0, reset, '\\',
                            nneof, strlen(nneof));
                break;
        case DIFF_SYMBOL_SUBMODULE_HEADER:
@@ -1276,7 +1299,9 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
                        else if (c == '-')
                                set = diff_get_color_opt(o, DIFF_FILE_OLD);
                }
-               emit_line_ws_markup(o, set, reset, line, len, set_sign, ' ',
+               emit_line_ws_markup(o, set_sign, set, reset,
+                                   o->output_indicators[OUTPUT_INDICATOR_CONTEXT],
+                                   line, len,
                                    flags & (DIFF_SYMBOL_CONTENT_WS_MASK), 0);
                break;
        case DIFF_SYMBOL_PLUS:
@@ -1319,7 +1344,9 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
                                set = diff_get_color_opt(o, DIFF_CONTEXT_BOLD);
                        flags &= ~DIFF_SYMBOL_CONTENT_WS_MASK;
                }
-               emit_line_ws_markup(o, set, reset, line, len, set_sign, '+',
+               emit_line_ws_markup(o, set_sign, set, reset,
+                                   o->output_indicators[OUTPUT_INDICATOR_NEW],
+                                   line, len,
                                    flags & DIFF_SYMBOL_CONTENT_WS_MASK,
                                    flags & DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF);
                break;
@@ -1362,7 +1389,9 @@ static void emit_diff_symbol_from_struct(struct diff_options *o,
                        else
                                set = diff_get_color_opt(o, DIFF_CONTEXT_DIM);
                }
-               emit_line_ws_markup(o, set, reset, line, len, set_sign, '-',
+               emit_line_ws_markup(o, set_sign, set, reset,
+                                   o->output_indicators[OUTPUT_INDICATOR_OLD],
+                                   line, len,
                                    flags & DIFF_SYMBOL_CONTENT_WS_MASK, 0);
                break;
        case DIFF_SYMBOL_WORDS_PORCELAIN:
@@ -2937,16 +2966,11 @@ static void show_dirstat(struct diff_options *options)
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
-               int content_changed;
 
                name = p->two->path ? p->two->path : p->one->path;
 
-               if (p->one->oid_valid && p->two->oid_valid)
-                       content_changed = oidcmp(&p->one->oid, &p->two->oid);
-               else
-                       content_changed = 1;
-
-               if (!content_changed) {
+               if (p->one->oid_valid && p->two->oid_valid &&
+                   oideq(&p->one->oid, &p->two->oid)) {
                        /*
                         * The SHA1 has not changed, so pre-/post-content is
                         * identical. We can therefore skip looking at the
@@ -2994,7 +3018,7 @@ static void show_dirstat(struct diff_options *options)
                 * made to the preimage.
                 * If the resulting damage is zero, we know that
                 * diffcore_count_changes() considers the two entries to
-                * be identical, but since content_changed is true, we
+                * be identical, but since the oid changed, we
                 * know that there must have been _some_ kind of change,
                 * so we force all entries to have damage > 0.
                 */
@@ -3412,7 +3436,7 @@ static void builtin_diff(const char *name_a,
                if (!one->data && !two->data &&
                    S_ISREG(one->mode) && S_ISREG(two->mode) &&
                    !o->flags.binary) {
-                       if (!oidcmp(&one->oid, &two->oid)) {
+                       if (oideq(&one->oid, &two->oid)) {
                                if (must_show_header)
                                        emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
                                                         header.buf, header.len,
@@ -3578,7 +3602,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                return;
        }
 
-       same_contents = !oidcmp(&one->oid, &two->oid);
+       same_contents = oideq(&one->oid, &two->oid);
 
        if (diff_filespec_is_binary(o->repo, one) ||
            diff_filespec_is_binary(o->repo, two)) {
@@ -3780,7 +3804,7 @@ static int reuse_worktree_file(struct index_state *istate,
         * This is not the sha1 we are looking for, or
         * unreusable because it is not a regular file.
         */
-       if (oidcmp(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
+       if (!oideq(oid, &ce->oid) || !S_ISREG(ce->ce_mode))
                return 0;
 
        /*
@@ -4190,7 +4214,7 @@ static void fill_metainfo(struct strbuf *msg,
        default:
                *must_show_header = 0;
        }
-       if (one && two && oidcmp(&one->oid, &two->oid)) {
+       if (one && two && !oideq(&one->oid, &two->oid)) {
                const unsigned hexsz = the_hash_algo->hexsz;
                int abbrev = o->flags.full_index ? hexsz : DEFAULT_ABBREV;
 
@@ -4403,6 +4427,9 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
        options->file = stdout;
        options->repo = r;
 
+       options->output_indicators[OUTPUT_INDICATOR_NEW] = '+';
+       options->output_indicators[OUTPUT_INDICATOR_OLD] = '-';
+       options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = ' ';
        options->abbrev = DEFAULT_ABBREV;
        options->line_termination = '\n';
        options->break_opt = -1;
@@ -4880,6 +4907,12 @@ int diff_opt_parse(struct diff_options *options,
                 options->output_format |= DIFF_FORMAT_DIFFSTAT;
        } else if (!strcmp(arg, "--no-compact-summary"))
                 options->flags.stat_with_summary = 0;
+       else if (skip_prefix(arg, "--output-indicator-new=", &arg))
+               options->output_indicators[OUTPUT_INDICATOR_NEW] = arg[0];
+       else if (skip_prefix(arg, "--output-indicator-old=", &arg))
+               options->output_indicators[OUTPUT_INDICATOR_OLD] = arg[0];
+       else if (skip_prefix(arg, "--output-indicator-context=", &arg))
+               options->output_indicators[OUTPUT_INDICATOR_CONTEXT] = arg[0];
 
        /* renames options */
        else if (starts_with(arg, "-B") ||
@@ -5351,7 +5384,7 @@ int diff_unmodified_pair(struct diff_filepair *p)
         * dealing with a change.
         */
        if (one->oid_valid && two->oid_valid &&
-           !oidcmp(&one->oid, &two->oid) &&
+           oideq(&one->oid, &two->oid) &&
            !one->dirty_submodule && !two->dirty_submodule)
                return 1; /* no change */
        if (!one->oid_valid && !two->oid_valid)
@@ -5485,7 +5518,7 @@ static void diff_resolve_rename_copy(void)
                        else
                                p->status = DIFF_STATUS_RENAMED;
                }
-               else if (oidcmp(&p->one->oid, &p->two->oid) ||
+               else if (!oideq(&p->one->oid, &p->two->oid) ||
                         p->one->mode != p->two->mode ||
                         p->one->dirty_submodule ||
                         p->two->dirty_submodule ||
@@ -5847,8 +5880,8 @@ static void diff_flush_patch_all_file_pairs(struct diff_options *o)
                        if (o->color_moved == COLOR_MOVED_ZEBRA_DIM)
                                dim_moved_lines(o);
 
-                       hashmap_free(&add_lines, 0);
-                       hashmap_free(&del_lines, 0);
+                       hashmap_free(&add_lines, 1);
+                       hashmap_free(&del_lines, 1);
                }
 
                for (i = 0; i < esm.nr; i++)