605
#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<16)
606
#define DIFF_SYMBOL_CONTENT_WS_MASK (WSEH_NEW | WSEH_OLD | WSEH_CONTEXT | WS_RULE_MASK)
607
608
+/*
609
+ * This struct is used when we need to buffer the output of the diff output.
610
+ *
611
+ * NEEDSWORK: Instead of storing a copy of the line, add an offset pointer
612
+ * into the pre/post image file. This pointer could be a union with the
613
+ * line pointer. By storing an offset into the file instead of the literal line,
614
+ * we can decrease the memory footprint for the buffered output. At first we
615
+ * may want to only have indirection for the content lines, but we could also
616
+ * enhance the state for emitting prefabricated lines, e.g. the similarity
617
+ * score line or hunk/file headers would only need to store a number or path
618
+ * and then the output can be constructed later on depending on state.
619
+ */
620
+struct emitted_diff_symbol {
621
+ const char *line;
622
+ int len;
623
+ int flags;
624
+ enum diff_symbol s;
625
+};
626
+#define EMITTED_DIFF_SYMBOL_INIT {NULL}
627
+
628
+struct emitted_diff_symbols {
629
+ struct emitted_diff_symbol *buf;
630
+ int nr, alloc;
631
+};
632
+#define EMITTED_DIFF_SYMBOLS_INIT {NULL, 0, 0}
633
+
634
+static void append_emitted_diff_symbol(struct diff_options *o,
635
+ struct emitted_diff_symbol *e)
636
+{
637
+ struct emitted_diff_symbol *f;
638
+
639
+ ALLOC_GROW(o->emitted_symbols->buf,
640
+ o->emitted_symbols->nr + 1,
641
+ o->emitted_symbols->alloc);
642
+ f = &o->emitted_symbols->buf[o->emitted_symbols->nr++];
643
+
644
+ memcpy(f, e, sizeof(struct emitted_diff_symbol));
645
+ f->line = e->line ? xmemdupz(e->line, e->len) : NULL;
646
+}
647
+
648
+
649
static void emit_line_ws_markup(struct diff_options *o,
650
const char *set, const char *reset,
651
const char *line, int len, char sign,
672
}
673
}
674
634
-static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
635
- const char *line, int len, unsigned flags)
675
+static void emit_diff_symbol_from_struct(struct diff_options *o,
676
+ struct emitted_diff_symbol *eds)
677
{
678
static const char *nneof = " No newline at end of file\n";
679
const char *context, *reset, *set, *meta, *fraginfo;
680
struct strbuf sb = STRBUF_INIT;
681
+
682
+ enum diff_symbol s = eds->s;
683
+ const char *line = eds->line;
684
+ int len = eds->len;
685
+ unsigned flags = eds->flags;
686
+
687
switch (s) {
688
case DIFF_SYMBOL_NO_LF_EOF:
689
context = diff_get_color_opt(o, DIFF_CONTEXT);
825
strbuf_release(&sb);
826
}
827
828
+static void emit_diff_symbol(struct diff_options *o, enum diff_symbol s,
829
+ const char *line, int len, unsigned flags)
830
+{
831
+ struct emitted_diff_symbol e = {line, len, flags, s};
832
+
833
+ if (o->emitted_symbols)
834
+ append_emitted_diff_symbol(o, &e);
835
+ else
836
+ emit_diff_symbol_from_struct(o, &e);
837
+}
838
+
839
void diff_emit_submodule_del(struct diff_options *o, const char *line)
840
{
841
emit_diff_symbol(o, DIFF_SYMBOL_SUBMODULE_DEL, line, strlen(line), 0);
1432
/* In "color-words" mode, show word-diff of words accumulated in the buffer */
1433
static void diff_words_flush(struct emit_callback *ecbdata)
1434
{
1435
+ struct diff_options *wo = ecbdata->diff_words->opt;
1436
+
1437
if (ecbdata->diff_words->minus.text.size ||
1438
ecbdata->diff_words->plus.text.size)
1439
diff_words_show(ecbdata->diff_words);
1440
+
1441
+ if (wo->emitted_symbols) {
1442
+ struct diff_options *o = ecbdata->opt;
1443
+ struct emitted_diff_symbols *wol = wo->emitted_symbols;
1444
+ int i;
1445
+
1446
+ /*
1447
+ * NEEDSWORK:
1448
+ * Instead of appending each, concat all words to a line?
1449
+ */
1450
+ for (i = 0; i < wol->nr; i++)
1451
+ append_emitted_diff_symbol(o, &wol->buf[i]);
1452
+
1453
+ for (i = 0; i < wol->nr; i++)
1454
+ free((void *)wol->buf[i].line);
1455
+
1456
+ wol->nr = 0;
1457
+ }
1458
}
1459
1460
static void diff_filespec_load_driver(struct diff_filespec *one)
1490
xcalloc(1, sizeof(struct diff_words_data));
1491
ecbdata->diff_words->type = o->word_diff;
1492
ecbdata->diff_words->opt = o;
1493
+
1494
+ if (orig_opts->emitted_symbols)
1495
+ o->emitted_symbols =
1496
+ xcalloc(1, sizeof(struct emitted_diff_symbols));
1497
+
1498
if (!o->word_regex)
1499
o->word_regex = userdiff_word_regex(one);
1500
if (!o->word_regex)
1529
{
1530
if (ecbdata->diff_words) {
1531
diff_words_flush(ecbdata);
1532
+ free (ecbdata->diff_words->opt->emitted_symbols);
1533
free (ecbdata->diff_words->opt);
1534
free (ecbdata->diff_words->minus.text.ptr);
1535
free (ecbdata->diff_words->minus.orig);
5080
static void diff_flush_patch_all_file_pairs(struct diff_options *o)
5081
{
5082
int i;
5083
+ static struct emitted_diff_symbols esm = EMITTED_DIFF_SYMBOLS_INIT;
5084
struct diff_queue_struct *q = &diff_queued_diff;
5085
5086
if (WSEH_NEW & WS_RULE_MASK)
5087
die("BUG: WS rules bit mask overlaps with diff symbol flags");
5088
5089
+ /*
5090
+ * For testing purposes we want to make sure the diff machinery
5091
+ * works completely with the buffer. If there is anything emitted
5092
+ * outside the emit_string, then the order is screwed
5093
+ * up and the tests will fail.
5094
+ *
5095
+ * TODO (later in this series):
5096
+ * We'll unset this pointer in a later patch.
5097
+ */
5098
+ o->emitted_symbols = &esm;
5099
+
5100
for (i = 0; i < q->nr; i++) {
5101
struct diff_filepair *p = q->queue[i];
5102
if (check_pair_status(p))
5103
diff_flush_patch(p, o);
5104
}
5105
+
5106
+ if (o->emitted_symbols) {
5107
+ for (i = 0; i < esm.nr; i++)
5108
+ emit_diff_symbol_from_struct(o, &esm.buf[i]);
5109
+
5110
+ for (i = 0; i < esm.nr; i++)
5111
+ free((void *)esm.buf[i].line);
5112
+ }
5113
+ esm.nr = 0;
5114
}
5115
5116
void diff_flush(struct diff_options *options)