--- diffstat-1.39/diffstat.c.orig Thu Aug 4 10:04:37 2005 +++ diffstat-1.39/diffstat.c Fri Aug 12 14:37:07 2005 @@ -893,30 +893,77 @@ } /* - * Each call to 'plot_num()' prints a scaled bar of 'c' characters. The - * 'extra' parameter is used to keep the accumulated error in the bar's total - * length from getting large. + * Print a scaled bar of characters, where c[0] is for insertions, c[1] + * for deletions and c[2] for modifications. The num array contains the + * count for each type of change, in the same order. */ -static long -plot_num(long num_value, int c, long extra) +static void +plot_num(long *num, char *c) { - switch (format_opt) { - case 0: - printf("\t%ld %c", num_value, c); - return 0; - default: - /* the value to plot */ - /* character to display in the bar */ - /* accumulated error in the bar */ - { - long product = (plot_width * num_value) + extra; - long count = (product / plot_scale); - extra = product - (count * plot_scale); - while (--count >= 0) - (void) putchar(c); - return extra; + long scaled[3], remain[3], total; + int i; + + for (total = 0, i = 0; i < 3; i++) + total += num[i]; + printf("%5ld ", total); + + if (format_opt == 0) { + for (i = 0; i < 3; i++) + printf("\t%ld %c", num[i], c[i]); + return; + } + + if (total == 0) + return; + + total = (total * plot_width + (plot_scale/2)) / plot_scale; + /* display at least one character */ + if (total == 0) + total++; + + for (i = 0; i < 3; i++) { + scaled[i] = num[i] * plot_width / plot_scale; + remain[i] = num[i] * plot_width - scaled[i] * plot_scale; + total -= scaled[i]; + } + + /* assign the missing chars using the largest remainder algo */ + while (total) { + int largest, largest_count; /* largest is a bit field */ + long max_remain; + + /* search for the largest remainder */ + largest = largest_count = 0; + max_remain = 0; + for (i = 0; i < 3; i++) { + if (remain[i] > max_remain) { + largest = 1 << i; + largest_count = 1; + max_remain = remain[i]; + } else if (remain[i] == max_remain) { /* ex aequo */ + largest |= 1 << i; + largest_count++; + } + } + + /* if there are more greatest remainders than characters + missing, don't assign them at all */ + if (total < largest_count) + break; + + /* allocate the extra characters */ + for (i = 0; i < 3; i++) { + if (largest & (1 << i)) { + scaled[i]++; + total--; + remain[i] -= plot_width; + } } } + + for (i = 0; i < 3; i++) + while (--scaled[i] >= 0) + (void) putchar(c[i]); } static void @@ -924,6 +971,7 @@ { DATA *p; long total_ins = 0, total_del = 0, total_mod = 0, temp; + long plot_data[3]; int num_files = 0, shortest_name = -1, longest_name = -1, prefix_len = -1; plot_scale = 0; @@ -988,11 +1036,10 @@ switch (p->cmt) { default: case Normal: - temp = 0; - printf("%5ld ", p->ins + p->del + p->mod); - temp = plot_num(p->ins, '+', temp); - (void) plot_num(p->del, '-', temp); - (void) plot_num(p->mod, '!', temp); + plot_data[0] = p->ins; + plot_data[1] = p->del; + plot_data[2] = p->mod; + plot_num(plot_data, "+-!"); break; case Binary: printf("binary");