[T_RD] = "rd",
[T_ROUTE] = "route",
+ [T_ROUTES_BLOCK] = "block of routes",
};
const char *
case T_CLIST: return T_PAIR;
case T_ECLIST: return T_EC;
case T_LCLIST: return T_LC;
+ case T_ROUTES_BLOCK: return T_ROUTE;
default: return T_VOID;
};
}
case T_STRING:
return strcmp(v1->val.s, v2->val.s);
case T_ROUTE:
+ case T_ROUTES_BLOCK:
default:
return F_CMP_ERROR;
}
return trie_same(v1->val.ti, v2->val.ti);
case T_ROUTE:
return rte_same(v1->val.rte, v2->val.rte);
+ case T_ROUTES_BLOCK:
+ for (
+ rte *r1 = v1->val.rte, *r2 = v2->val.rte;
+ r1 || r2;
+ r1 = r1->next, r2 = r2->next
+ )
+ if (!r1 || !r2 || !rte_same(r1, r2))
+ return 0;
+ return 1;
default:
bug("Invalid type in val_same(): %x", v1->type);
}
buffer_puts(buf, "[No route]");
}
+static void
+rte_block_format(const struct rte *rte, buffer *buf)
+{
+ buffer_print(buf, "Block of routes:");
+
+ for (int i = 0; rte; rte = rte->next, i++)
+ {
+ buffer_print(buf, "%s%d: ", i ? "; " : " ", i);
+ rte_format(rte, buf);
+ }
+}
+
+
/*
* val_format - format filter value
*/
case T_LCLIST: lc_set_format(v->val.ad, -1, buf2, 1000); buffer_print(buf, "(lclist %s)", buf2); return;
case T_PATH_MASK: pm_format(v->val.path_mask, buf); return;
case T_ROUTE: rte_format(v->val.rte, buf); return;
+ case T_ROUTES_BLOCK: rte_block_format(v->val.rte, buf); return;
default: buffer_print(buf, "[unknown type %x]", v->type); return;
}
}
METHOD_CONSTRUCTOR("!for_next");
}
+ INST(FI_ROUTES_BLOCK_FOR_NEXT, 3, 0) {
+ NEVER_CONSTANT;
+ ARG(1, T_ROUTES_BLOCK);
+
+ /* Loop auxiliary variable is initialized to T_VOID.
+ * In the first run, we initialize the auxiliary variable
+ * to the routes block supplied. It changes its type
+ * to T_ROUTES_BLOCK and therefore won't be run again. */
+ if (v2.type == T_VOID)
+ v2 = v1;
+
+ if (v2.val.rte)
+ {
+ /* There is some route to process, set it into the iterator variable.
+ * Its type has been already initialized by f_for_cycle(). */
+ v3.val.rte = v2.val.rte;
+ v3.val.eattrs = v3.val.rte->attrs->eattrs;
+
+ /* Prepare next route in the loop auxiliary variable */
+ v2.val.rte = v2.val.rte->next;
+
+ /* And execute the line */
+ LINE(2,0);
+ }
+
+ METHOD_CONSTRUCTOR("!for_next");
+ }
+
INST(FI_CONDITION, 1, 0) {
ARG(1, T_BOOL);
if (v1.val.i)