mirror of
https://github.com/git/git.git
synced 2024-11-27 03:53:55 +08:00
6932ec8183
In `prepare_order()` we parse an orderfile and assign it to a global array. In order to save on some allocations, we replace newlines with NUL characters and then assign pointers into the allocated buffer to that array. This can cause the buffer to be completely unreferenced though in some cases, e.g. because the order file is empty or because we had to use `xmemdupz()` to copy the lines instead of NUL-terminating them. Refactor the code to always `xmemdupz()` the strings. This is a bit simpler, and it is rather unlikely that saving a handful of allocations really matters. This allows us to release the string buffer and thus plug the memory leak. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
129 lines
2.4 KiB
C
129 lines
2.4 KiB
C
/*
|
|
* Copyright (C) 2005 Junio C Hamano
|
|
*/
|
|
#include "git-compat-util.h"
|
|
#include "gettext.h"
|
|
#include "diff.h"
|
|
#include "diffcore.h"
|
|
#include "wildmatch.h"
|
|
|
|
static char **order;
|
|
static int order_cnt;
|
|
|
|
static void prepare_order(const char *orderfile)
|
|
{
|
|
int cnt, pass;
|
|
struct strbuf sb = STRBUF_INIT;
|
|
const char *cp, *endp;
|
|
ssize_t sz;
|
|
|
|
if (order)
|
|
return;
|
|
|
|
sz = strbuf_read_file(&sb, orderfile, 0);
|
|
if (sz < 0)
|
|
die_errno(_("failed to read orderfile '%s'"), orderfile);
|
|
endp = sb.buf + sz;
|
|
|
|
for (pass = 0; pass < 2; pass++) {
|
|
cnt = 0;
|
|
cp = sb.buf;
|
|
while (cp < endp) {
|
|
const char *ep;
|
|
for (ep = cp; ep < endp && *ep != '\n'; ep++)
|
|
;
|
|
/* cp to ep has one line */
|
|
if (*cp == '\n' || *cp == '#')
|
|
; /* comment */
|
|
else if (pass == 0)
|
|
cnt++;
|
|
else {
|
|
order[cnt] = xmemdupz(cp, ep - cp);
|
|
cnt++;
|
|
}
|
|
if (ep < endp)
|
|
ep++;
|
|
cp = ep;
|
|
}
|
|
if (pass == 0) {
|
|
order_cnt = cnt;
|
|
ALLOC_ARRAY(order, cnt);
|
|
}
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
}
|
|
|
|
static int match_order(const char *path)
|
|
{
|
|
int i;
|
|
static struct strbuf p = STRBUF_INIT;
|
|
|
|
for (i = 0; i < order_cnt; i++) {
|
|
strbuf_reset(&p);
|
|
strbuf_addstr(&p, path);
|
|
while (p.buf[0]) {
|
|
char *cp;
|
|
if (!wildmatch(order[i], p.buf, 0))
|
|
return i;
|
|
cp = strrchr(p.buf, '/');
|
|
if (!cp)
|
|
break;
|
|
*cp = 0;
|
|
}
|
|
}
|
|
return order_cnt;
|
|
}
|
|
|
|
static int compare_objs_order(const void *a_, const void *b_)
|
|
{
|
|
struct obj_order const *a, *b;
|
|
a = (struct obj_order const *)a_;
|
|
b = (struct obj_order const *)b_;
|
|
if (a->order != b->order)
|
|
return a->order - b->order;
|
|
return a->orig_order - b->orig_order;
|
|
}
|
|
|
|
void order_objects(const char *orderfile, obj_path_fn_t obj_path,
|
|
struct obj_order *objs, int nr)
|
|
{
|
|
int i;
|
|
|
|
if (!nr)
|
|
return;
|
|
|
|
prepare_order(orderfile);
|
|
for (i = 0; i < nr; i++) {
|
|
objs[i].orig_order = i;
|
|
objs[i].order = match_order(obj_path(objs[i].obj));
|
|
}
|
|
QSORT(objs, nr, compare_objs_order);
|
|
}
|
|
|
|
static const char *pair_pathtwo(void *obj)
|
|
{
|
|
struct diff_filepair *pair = (struct diff_filepair *)obj;
|
|
|
|
return pair->two->path;
|
|
}
|
|
|
|
void diffcore_order(const char *orderfile)
|
|
{
|
|
struct diff_queue_struct *q = &diff_queued_diff;
|
|
struct obj_order *o;
|
|
int i;
|
|
|
|
if (!q->nr)
|
|
return;
|
|
|
|
ALLOC_ARRAY(o, q->nr);
|
|
for (i = 0; i < q->nr; i++)
|
|
o[i].obj = q->queue[i];
|
|
order_objects(orderfile, pair_pathtwo, o, q->nr);
|
|
for (i = 0; i < q->nr; i++)
|
|
q->queue[i] = o[i].obj;
|
|
free(o);
|
|
return;
|
|
}
|