}
/* tack on a _new_ range _at the end_ */
-static void range_set_append(struct range_set *rs, long a, long b)
+static void range_set_append_unsafe(struct range_set *rs, long a, long b)
{
assert(a <= b);
- assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
range_set_grow(rs, 1);
rs->ranges[rs->nr].start = a;
rs->ranges[rs->nr].end = b;
rs->nr++;
}
+static void range_set_append(struct range_set *rs, long a, long b)
+{
+ assert(rs->nr == 0 || rs->ranges[rs->nr-1].end <= a);
+ range_set_append_unsafe(rs, a, b);
+}
+
static int range_cmp(const void *_r, const void *_s)
{
const struct range *r = _r;
}
/*
- * Helper: In-place pass of sorting and merging the ranges in the
- * range set, to re-establish the invariants after another operation
- *
- * NEEDSWORK currently not needed
+ * Check that the ranges are non-empty, sorted and non-overlapping
+ */
+static void range_set_check_invariants(struct range_set *rs)
+{
+ int i;
+
+ if (!rs)
+ return;
+
+ if (rs->nr)
+ assert(rs->ranges[0].start < rs->ranges[0].end);
+
+ for (i = 1; i < rs->nr; i++) {
+ assert(rs->ranges[i-1].end < rs->ranges[i].start);
+ assert(rs->ranges[i].start < rs->ranges[i].end);
+ }
+}
+
+/*
+ * In-place pass of sorting and merging the ranges in the range set,
+ * to establish the invariants when we get the ranges from the user
*/
static void sort_and_merge_range_set(struct range_set *rs)
{
}
assert(o <= rs->nr);
rs->nr = o;
+
+ range_set_check_invariants(rs);
}
/*
if (insertion_point)
*insertion_point = NULL;
while (p) {
- int cmp = strcmp(p->spec->path, path);
+ int cmp = strcmp(p->path, path);
if (!cmp)
return p;
if (insertion_point && cmp < 0)
return NULL;
}
+/*
+ * Note: takes ownership of 'path', which happens to be what the only
+ * caller needs.
+ */
static void line_log_data_insert(struct line_log_data **list,
- struct diff_filespec *spec,
+ char *path,
long begin, long end)
{
struct line_log_data *ip;
- struct line_log_data *p = search_line_log_data(*list, spec->path, &ip);
+ struct line_log_data *p = search_line_log_data(*list, path, &ip);
if (p) {
- range_set_append(&p->ranges, begin, end);
+ range_set_append_unsafe(&p->ranges, begin, end);
sort_and_merge_range_set(&p->ranges);
- free_filespec(spec);
+ free(path);
return;
}
p = xcalloc(1, sizeof(struct line_log_data));
- p->spec = spec;
+ p->path = path;
range_set_append(&p->ranges, begin, end);
if (ip) {
p->next = ip->next;
{
char buf[4096];
while (r) {
- snprintf(buf, 4096, "file %s\n", r->spec->path);
+ snprintf(buf, 4096, "file %s\n", r->path);
dump_range_set(&r->ranges, buf);
r = r->next;
}
for_each_string_list_item(item, args) {
const char *name_part, *range_part;
- const char *full_name;
+ char *full_name;
struct diff_filespec *spec;
long begin = 0, end = 0;
if (parse_range_arg(range_part, nth_line, &cb_data,
lines, &begin, &end,
- spec->path))
+ full_name))
die("malformed -L argument '%s'", range_part);
if (begin < 1)
begin = 1;
begin--;
if (lines < end || lines < begin)
die("file %s has only %ld lines", name_part, lines);
- line_log_data_insert(&ranges, spec, begin, end);
+ line_log_data_insert(&ranges, full_name, begin, end);
+ free_filespec(spec);
free(ends);
ends = NULL;
}
line_log_data_init(ret);
range_set_copy(&ret->ranges, &r->ranges);
- ret->spec = r->spec;
- assert(ret->spec);
- ret->spec->count++;
+ ret->path = xstrdup(r->path);
return ret;
}
else if (!b)
cmp = -1;
else
- cmp = strcmp(a->spec->path, b->spec->path);
+ cmp = strcmp(a->path, b->path);
if (cmp < 0) {
src = a;
a = a->next;
}
d = xmalloc(sizeof(struct line_log_data));
line_log_data_init(d);
- d->spec = src->spec;
- d->spec->count++;
+ d->path = xstrdup(src->path);
*pp = d;
pp = &d->next;
if (src2)
struct commit *commit)
{
struct line_log_data *ret = NULL;
+ struct line_log_data *d;
ret = lookup_decoration(&revs->line_log_data, &commit->object);
+
+ for (d = ret; d; d = d->next)
+ range_set_check_invariants(&d->ranges);
+
return ret;
}
paths = xmalloc((count+1)*sizeof(char *));
r = range;
for (i = 0; i < count; i++) {
- paths[i] = xstrdup(r->spec->path);
+ paths[i] = xstrdup(r->path);
r = r->next;
}
paths[count] = NULL;
continue;
}
for (rg = range; rg; rg = rg->next) {
- if (!strcmp(rg->spec->path, p->two->path))
+ if (!strcmp(rg->path, p->two->path))
break;
}
if (rg)
assert(pair->two->path);
while (rg) {
- assert(rg->spec->path);
- if (!strcmp(rg->spec->path, pair->two->path))
+ assert(rg->path);
+ if (!strcmp(rg->path, pair->two->path))
break;
rg = rg->next;
}
collect_diff(&file_parent, &file_target, &diff);
/* NEEDSWORK should apply some heuristics to prevent mismatches */
- rg->spec->path = xstrdup(pair->one->path);
+ free(rg->path);
+ rg->path = xstrdup(pair->one->path);
range_set_init(&tmp, 0);
range_set_map_across_diff(&tmp, &rg->ranges, &diff, diff_out);
for (i = 0; i < queue->nr; i++) {
struct diff_ranges *pairdiff = NULL;
- if (process_diff_filepair(rev, queue->queue[i], *range_out, &pairdiff)) {
+ struct diff_filepair *pair = queue->queue[i];
+ if (process_diff_filepair(rev, pair, *range_out, &pairdiff)) {
+ /*
+ * Store away the diff for later output. We
+ * tuck it in the ranges we got as _input_,
+ * since that's the commit that caused the
+ * diff.
+ *
+ * NEEDSWORK not enough when we get around to
+ * doing something interesting with merges;
+ * currently each invocation on a merge parent
+ * trashes the previous one's diff.
+ *
+ * NEEDSWORK tramples over data structures not owned here
+ */
struct line_log_data *rg = range;
changed++;
- /* NEEDSWORK tramples over data structures not owned here */
- while (rg && strcmp(rg->spec->path, queue->queue[i]->two->path))
+ while (rg && strcmp(rg->path, pair->two->path))
rg = rg->next;
assert(rg);
rg->pair = diff_filepair_dup(queue->queue[i]);