summaryrefslogtreecommitdiff
path: root/diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'diff.c')
-rw-r--r--diff.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/diff.c b/diff.c
index 397e38b41c..1a3b19f71f 100644
--- a/diff.c
+++ b/diff.c
@@ -2927,6 +2927,28 @@ void print_stat_summary(FILE *fp, int files,
print_stat_summary_inserts_deletes(&o, files, insertions, deletions);
}
+/*
+ * Like utf8_width(), but guaranteed safe for use in loops that subtract
+ * per-character widths:
+ *
+ * - utf8_width() sets *start to NULL on invalid UTF-8 and returns 0;
+ * we restore the pointer and advance by one byte, returning width 1
+ * (matching the strlen()-based fallback in utf8_strwidth()).
+ *
+ * - utf8_width() returns -1 for control characters; we return 0
+ * (matching utf8_strnwidth() which skips them).
+ */
+static int utf8_ish_width(const char **start)
+{
+ const char *old = *start;
+ int w = utf8_width(start, NULL);
+ if (!*start) {
+ *start = old + 1;
+ return 1;
+ }
+ return (w < 0) ? 0 : w;
+}
+
static void show_stats(struct diffstat_t *data, struct diff_options *options)
{
int i, len, add, del, adds = 0, dels = 0;
@@ -3093,8 +3115,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
if (len < 0)
len = 0;
- while (name_len > len)
- name_len -= utf8_width((const char**)&name, NULL);
+ while (name_len > len && *name)
+ name_len -= utf8_ish_width((const char**)&name);
slash = strchr(name, '/');
if (slash)