diff options
Diffstat (limited to 'nest/a-path.c')
-rw-r--r-- | nest/a-path.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/nest/a-path.c b/nest/a-path.c index 63ac402e..dc36e653 100644 --- a/nest/a-path.c +++ b/nest/a-path.c @@ -244,10 +244,11 @@ as_path_get_first(struct adata *path, u32 *last_as) } int -as_path_is_member(struct adata *path, u32 as) +as_path_contains(struct adata *path, u32 as, int min) { u8 *p = path->data; u8 *q = p+path->length; + int num = 0; int i, n; while (p<q) @@ -257,13 +258,100 @@ as_path_is_member(struct adata *path, u32 as) for(i=0; i<n; i++) { if (get_as(p) == as) + if (++num == min) + return 1; + p += BS; + } + } + return 0; +} + +int +as_path_match_set(struct adata *path, struct f_tree *set) +{ + u8 *p = path->data; + u8 *q = p+path->length; + int i, n; + + while (p<q) + { + n = p[1]; + p += 2; + for (i=0; i<n; i++) + { + struct f_val v = {T_INT, .val.i = get_as(p)}; + if (find_tree(set, v)) return 1; p += BS; } } + return 0; } +struct adata * +as_path_filter(struct linpool *pool, struct adata *path, struct f_tree *set, u32 key, int pos) +{ + if (!path) + return NULL; + + int len = path->length; + u8 *p = path->data; + u8 *q = path->data + len; + u8 *d, *d2; + int i, bt, sn, dn; + u8 buf[len]; + + d = buf; + while (p<q) + { + /* Read block header (type and length) */ + bt = p[0]; + sn = p[1]; + dn = 0; + p += 2; + d2 = d + 2; + + for (i = 0; i < sn; i++) + { + u32 as = get_as(p); + int match; + + if (set) + match = !!find_tree(set, (struct f_val){T_INT, .val.i = as}); + else + match = (as == key); + + if (match == pos) + { + put_as(d2, as); + d2 += BS; + dn++; + } + + p += BS; + } + + if (dn > 0) + { + /* Nonempty block, set block header and advance */ + d[0] = bt; + d[1] = dn; + d = d2; + } + } + + int nl = d - buf; + if (nl == path->length) + return path; + + struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl); + res->length = nl; + memcpy(res->data, buf, nl); + + return res; +} + struct pm_pos { |