static void convert_options(const struct config_parser *parser, struct group *parent, unsigned parent_index, struct group **next_group, void ***next_input_slot) { const struct config_parser **children = parser->children; struct group *group = (*next_group)++; group->parser = parser; group->parent = parent; group->parent_index = parent_index; if (!children) group->state.child_inputs = NULL; else { size_t num_children; size_t i; for (num_children = 0; children[num_children]; num_children++) ; group->state.child_inputs = *next_input_slot; *next_input_slot += num_children; for (i = 0; i < num_children; i++) convert_options(children[i], group, i, next_group, next_input_slot); } }
/* Initialize GROUP from ARGP. If CVT->SHORT_END is non-NULL, short * options are recorded in the short options string. Returns the next * unused group entry. CVT holds state used during the conversion. */ static struct group * convert_options (const struct argp *argp, struct group *parent, unsigned parent_index, struct group *group, struct parser_convert_state *cvt) { const struct argp_option *opt = argp->options; const struct argp_child *children = argp->children; if (opt || argp->parser) { /* This parser needs a group. */ if (cvt->short_end) { /* Record any short options. */ for (; !__option_is_end(opt); opt++) { if (opt && __option_is_short(opt)) { *cvt->short_end++ = (char)opt->key; } } } group->parser = argp->parser; group->argp = argp; group->args_processed = 0; group->parent = parent; group->parent_index = parent_index; group->input = 0; group->hook = 0; group->child_inputs = 0; if (children) /* Assign GROUP's CHILD_INPUTS field some space from CVT->child_inputs_end.*/ { unsigned num_children = 0; while (children[num_children].argp) num_children++; group->child_inputs = cvt->child_inputs_end; cvt->child_inputs_end += num_children; } parent = group++; } else { parent = 0; } if (children) { unsigned local_index = 0; while (children->argp) { group = convert_options(children++->argp, parent, local_index++, group, cvt); } } return group; }
/* Allocate and initialize the group structures, so that they are ordered as if by traversing the corresponding argp parser tree in pre-order. Also build the list of short options, if that is needed. */ static void parser_convert (struct parser *parser, const struct argp *argp) { struct parser_convert_state cvt; cvt.parser = parser; cvt.short_end = parser->short_opts; cvt.child_inputs_end = parser->child_inputs; parser->argp = argp; if (argp) parser->egroup = convert_options (argp, 0, 0, parser->groups, &cvt); else parser->egroup = parser->groups; /* No parsers at all! */ if (parser->short_opts) *cvt.short_end ='\0'; }
static int parser_init(struct parser_state *state, const struct config_parser *parser, void *input) { struct parser_sizes szs; size_t group_alloc; size_t input_alloc; void **next_input_slot; struct group *group; /* Allocate and initialize group structures */ init_sizes(&szs); calc_sizes(parser, &szs); group_alloc = sizeof(*state->groups) * szs.num_groups; input_alloc = sizeof(*state->child_inputs) * szs.num_child_inputs; state->storage = malloc(group_alloc + input_alloc); if (!state->storage) return ENOMEM; state->groups = state->storage; state->egroup = state->groups + szs.num_groups; if (szs.num_child_inputs > 0) { state->child_inputs = (void *) ((char *) state->storage + group_alloc); memset(state->child_inputs, 0, input_alloc); } else state->child_inputs = NULL; group = state->groups; next_input_slot = state->child_inputs; convert_options(parser, NULL, 0, &group, &next_input_slot); assert(group == state->egroup); assert(next_input_slot == state->child_inputs + szs.num_child_inputs); /* Call with CONFIG_KEY_INIT, for propagation of child inputs */ state->groups[0].state.input = input; for (group = state->groups; group < state->egroup; group++) { int err; if (group->parent) group->state.input = group->parent->state.child_inputs[group->parent_index]; err = group->parser->handler(CONFIG_PARSE_KEY_INIT, 0, NULL, &group->state); if (err && err != EINVAL) { /* Abort initialization */ free(state->storage); state->storage = NULL; return err; } } return 0; }