For what it's worth, perhaps you're using the wrong programming language :) What you intended to write is pretty much C++, where it'd be:
traverse(node, [node,h]{ print(node, h); });
Then, traverse would be a template function, so that you're not constrained to passing just one kind of a function, but instead could pass any functor (a callable object, e.g. a class implementing the call operator):
template <typename Fun> void traverse(node_t *, Fun &&f);
But you've used a function pointer, since it's C, and a function pointer is not like the C++ closure: it can carry no parameters. Thus, passing the parameters is on you. I imagine that the FILE* argument really comes from the node? Is that a directory tree you're trying to represent?
typedef struct {
node_t **children; // null-terminated array of child node pointers
const char *name;
} node_t;
typedef void (*cnode_observer_t)(const node_t *, int level, void *);
void ctraverse_level(const node_t *node, int level, void *extra,
cnode_observer_t cobserver)
{
cobserver(node, extra);
node_t **child = node->children;
++level;
while (*child) {
ctraverse_level(*child++, level, extra, cobserver);
}
}
void ctraverse(const node_t *node, void *extra, cnode_observer_t cobserver) {
ctraverse_level(node, 0, extra, cobserver);
}
void node_printer(const node_t *node, int level, void *file) {
assert(node && file);
FILE *f = file;
fprintf(f, "%*c%s\n", level, ' ', node->name);
}
void test(const node_t *node, FILE *file) {
ctraverse(node, file, node_printer);
}
For completeness' sake, here's how it'd look in C++:
struct Node {
std::vector<Node> children;
std::string name;
};
template <typename Obs>
void ctraverse(const Node &node, F fun, int level = 0) {
fun(node, level);
++level;
for (auto &n : node.children) {
ctraverse(n, fun);
}
}
void test(const Node &node, std::ostream &out) {
traverse(node, [&](auto &node, int level) {
out << setw(level) << setfill(' ') << " " << node.name << '\n';
});
}
traverseto pass parameters to the function passed in 3rd parameter.