|
|
|
@ -174,6 +174,154 @@ static struct diff_tempfile {
@@ -174,6 +174,154 @@ static struct diff_tempfile {
|
|
|
|
|
char tmp_path[PATH_MAX]; |
|
|
|
|
} diff_temp[2]; |
|
|
|
|
|
|
|
|
|
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); |
|
|
|
|
|
|
|
|
|
struct emit_callback { |
|
|
|
|
int color_diff; |
|
|
|
|
unsigned ws_rule; |
|
|
|
|
int blank_at_eof_in_preimage; |
|
|
|
|
int blank_at_eof_in_postimage; |
|
|
|
|
int lno_in_preimage; |
|
|
|
|
int lno_in_postimage; |
|
|
|
|
sane_truncate_fn truncate; |
|
|
|
|
const char **label_path; |
|
|
|
|
struct diff_words_data *diff_words; |
|
|
|
|
int *found_changesp; |
|
|
|
|
FILE *file; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static int count_lines(const char *data, int size) |
|
|
|
|
{ |
|
|
|
|
int count, ch, completely_empty = 1, nl_just_seen = 0; |
|
|
|
|
count = 0; |
|
|
|
|
while (0 < size--) { |
|
|
|
|
ch = *data++; |
|
|
|
|
if (ch == '\n') { |
|
|
|
|
count++; |
|
|
|
|
nl_just_seen = 1; |
|
|
|
|
completely_empty = 0; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
nl_just_seen = 0; |
|
|
|
|
completely_empty = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (completely_empty) |
|
|
|
|
return 0; |
|
|
|
|
if (!nl_just_seen) |
|
|
|
|
count++; /* no trailing newline */ |
|
|
|
|
return count; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) |
|
|
|
|
{ |
|
|
|
|
if (!DIFF_FILE_VALID(one)) { |
|
|
|
|
mf->ptr = (char *)""; /* does not matter */ |
|
|
|
|
mf->size = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
else if (diff_populate_filespec(one, 0)) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
mf->ptr = one->data; |
|
|
|
|
mf->size = one->size; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) |
|
|
|
|
{ |
|
|
|
|
char *ptr = mf->ptr; |
|
|
|
|
long size = mf->size; |
|
|
|
|
int cnt = 0; |
|
|
|
|
|
|
|
|
|
if (!size) |
|
|
|
|
return cnt; |
|
|
|
|
ptr += size - 1; /* pointing at the very end */ |
|
|
|
|
if (*ptr != '\n') |
|
|
|
|
; /* incomplete line */ |
|
|
|
|
else |
|
|
|
|
ptr--; /* skip the last LF */ |
|
|
|
|
while (mf->ptr < ptr) { |
|
|
|
|
char *prev_eol; |
|
|
|
|
for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) |
|
|
|
|
if (*prev_eol == '\n') |
|
|
|
|
break; |
|
|
|
|
if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) |
|
|
|
|
break; |
|
|
|
|
cnt++; |
|
|
|
|
ptr = prev_eol - 1; |
|
|
|
|
} |
|
|
|
|
return cnt; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, |
|
|
|
|
struct emit_callback *ecbdata) |
|
|
|
|
{ |
|
|
|
|
int l1, l2, at; |
|
|
|
|
unsigned ws_rule = ecbdata->ws_rule; |
|
|
|
|
l1 = count_trailing_blank(mf1, ws_rule); |
|
|
|
|
l2 = count_trailing_blank(mf2, ws_rule); |
|
|
|
|
if (l2 <= l1) { |
|
|
|
|
ecbdata->blank_at_eof_in_preimage = 0; |
|
|
|
|
ecbdata->blank_at_eof_in_postimage = 0; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
at = count_lines(mf1->ptr, mf1->size); |
|
|
|
|
ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; |
|
|
|
|
|
|
|
|
|
at = count_lines(mf2->ptr, mf2->size); |
|
|
|
|
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) |
|
|
|
|
{ |
|
|
|
|
int has_trailing_newline, has_trailing_carriage_return; |
|
|
|
|
|
|
|
|
|
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--; |
|
|
|
|
|
|
|
|
|
fputs(set, file); |
|
|
|
|
fwrite(line, len, 1, file); |
|
|
|
|
fputs(reset, file); |
|
|
|
|
if (has_trailing_carriage_return) |
|
|
|
|
fputc('\r', file); |
|
|
|
|
if (has_trailing_newline) |
|
|
|
|
fputc('\n', file); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) |
|
|
|
|
{ |
|
|
|
|
if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && |
|
|
|
|
ecbdata->blank_at_eof_in_preimage && |
|
|
|
|
ecbdata->blank_at_eof_in_postimage && |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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, |
|
|
|
|
ecbdata->file, set, reset, ws); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct diff_tempfile *claim_diff_tempfile(void) { |
|
|
|
|
int i; |
|
|
|
|
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) |
|
|
|
@ -201,29 +349,6 @@ static void remove_tempfile_on_signal(int signo)
@@ -201,29 +349,6 @@ static void remove_tempfile_on_signal(int signo)
|
|
|
|
|
raise(signo); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int count_lines(const char *data, int size) |
|
|
|
|
{ |
|
|
|
|
int count, ch, completely_empty = 1, nl_just_seen = 0; |
|
|
|
|
count = 0; |
|
|
|
|
while (0 < size--) { |
|
|
|
|
ch = *data++; |
|
|
|
|
if (ch == '\n') { |
|
|
|
|
count++; |
|
|
|
|
nl_just_seen = 1; |
|
|
|
|
completely_empty = 0; |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
nl_just_seen = 0; |
|
|
|
|
completely_empty = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (completely_empty) |
|
|
|
|
return 0; |
|
|
|
|
if (!nl_just_seen) |
|
|
|
|
count++; /* no trailing newline */ |
|
|
|
|
return count; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void print_line_count(FILE *file, int count) |
|
|
|
|
{ |
|
|
|
|
switch (count) { |
|
|
|
@ -337,21 +462,6 @@ static void emit_rewrite_diff(const char *name_a,
@@ -337,21 +462,6 @@ static void emit_rewrite_diff(const char *name_a,
|
|
|
|
|
copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) |
|
|
|
|
{ |
|
|
|
|
if (!DIFF_FILE_VALID(one)) { |
|
|
|
|
mf->ptr = (char *)""; /* does not matter */ |
|
|
|
|
mf->size = 0; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
else if (diff_populate_filespec(one, 0)) |
|
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
mf->ptr = one->data; |
|
|
|
|
mf->size = one->size; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct diff_words_buffer { |
|
|
|
|
mmfile_t text; |
|
|
|
|
long alloc; |
|
|
|
@ -529,22 +639,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
@@ -529,22 +639,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
|
|
|
|
|
diff_words->minus.text.size = diff_words->plus.text.size = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); |
|
|
|
|
|
|
|
|
|
struct emit_callback { |
|
|
|
|
int color_diff; |
|
|
|
|
unsigned ws_rule; |
|
|
|
|
int blank_at_eof_in_preimage; |
|
|
|
|
int blank_at_eof_in_postimage; |
|
|
|
|
int lno_in_preimage; |
|
|
|
|
int lno_in_postimage; |
|
|
|
|
sane_truncate_fn truncate; |
|
|
|
|
const char **label_path; |
|
|
|
|
struct diff_words_data *diff_words; |
|
|
|
|
int *found_changesp; |
|
|
|
|
FILE *file; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void free_diff_words_data(struct emit_callback *ecbdata) |
|
|
|
|
{ |
|
|
|
|
if (ecbdata->diff_words) { |
|
|
|
@ -570,55 +664,6 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
@@ -570,55 +664,6 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix)
|
|
|
|
|
return ""; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) |
|
|
|
|
{ |
|
|
|
|
int has_trailing_newline, has_trailing_carriage_return; |
|
|
|
|
|
|
|
|
|
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--; |
|
|
|
|
|
|
|
|
|
fputs(set, file); |
|
|
|
|
fwrite(line, len, 1, file); |
|
|
|
|
fputs(reset, file); |
|
|
|
|
if (has_trailing_carriage_return) |
|
|
|
|
fputc('\r', file); |
|
|
|
|
if (has_trailing_newline) |
|
|
|
|
fputc('\n', file); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) |
|
|
|
|
{ |
|
|
|
|
if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && |
|
|
|
|
ecbdata->blank_at_eof_in_preimage && |
|
|
|
|
ecbdata->blank_at_eof_in_postimage && |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
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); |
|
|
|
|
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, |
|
|
|
|
ecbdata->file, set, reset, ws); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len) |
|
|
|
|
{ |
|
|
|
|
const char *cp; |
|
|
|
@ -1450,51 +1495,6 @@ static const char *get_textconv(struct diff_filespec *one)
@@ -1450,51 +1495,6 @@ static const char *get_textconv(struct diff_filespec *one)
|
|
|
|
|
return one->driver->textconv; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) |
|
|
|
|
{ |
|
|
|
|
char *ptr = mf->ptr; |
|
|
|
|
long size = mf->size; |
|
|
|
|
int cnt = 0; |
|
|
|
|
|
|
|
|
|
if (!size) |
|
|
|
|
return cnt; |
|
|
|
|
ptr += size - 1; /* pointing at the very end */ |
|
|
|
|
if (*ptr != '\n') |
|
|
|
|
; /* incomplete line */ |
|
|
|
|
else |
|
|
|
|
ptr--; /* skip the last LF */ |
|
|
|
|
while (mf->ptr < ptr) { |
|
|
|
|
char *prev_eol; |
|
|
|
|
for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) |
|
|
|
|
if (*prev_eol == '\n') |
|
|
|
|
break; |
|
|
|
|
if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) |
|
|
|
|
break; |
|
|
|
|
cnt++; |
|
|
|
|
ptr = prev_eol - 1; |
|
|
|
|
} |
|
|
|
|
return cnt; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, |
|
|
|
|
struct emit_callback *ecbdata) |
|
|
|
|
{ |
|
|
|
|
int l1, l2, at; |
|
|
|
|
unsigned ws_rule = ecbdata->ws_rule; |
|
|
|
|
l1 = count_trailing_blank(mf1, ws_rule); |
|
|
|
|
l2 = count_trailing_blank(mf2, ws_rule); |
|
|
|
|
if (l2 <= l1) { |
|
|
|
|
ecbdata->blank_at_eof_in_preimage = 0; |
|
|
|
|
ecbdata->blank_at_eof_in_postimage = 0; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
at = count_lines(mf1->ptr, mf1->size); |
|
|
|
|
ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; |
|
|
|
|
|
|
|
|
|
at = count_lines(mf2->ptr, mf2->size); |
|
|
|
|
ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void builtin_diff(const char *name_a, |
|
|
|
|
const char *name_b, |
|
|
|
|
struct diff_filespec *one, |
|
|
|
|