static int _find_foreach_fn(void *data, size_t data_size, void *arg) { cfuopt_list_entry_t *opt = (cfuopt_list_entry_t *)data; _find_foreach_ds *ds = (_find_foreach_ds *)arg; size_t this_size = 0; cfulist_t *param_full_list = NULL; char *desc = NULL; _cfuopt_desc *desc_ds = CFU_OPT_ALLOC(_cfuopt_desc, 1); if (!data) return 0; param_full_list = cfulist_map(opt->param_names, _param_map_fn, opt); desc = cfulist_join(param_full_list, ", "); data_size = data_size; cfulist_destroy_with_free_fn(param_full_list, _simple_list_free_fn); desc_ds->desc = desc; desc_ds->entry = opt; cfulist_push(ds->desc_list, desc_ds); this_size = strlen(desc); if (this_size > ds->max_size) ds->max_size = this_size; return 0; }
extern void cfuopt_add_entry(cfuopt_t *context, const char *opt_str, void *arg_data, const char *description, const char *arg_description) { cfuopt_list_entry_t *entry = CFU_OPT_ALLOC(cfuopt_list_entry_t, 1); cfulist_t *param_list = NULL; cfuopt_arg_t arg_type = cfuopt_arg_invalid; struct _add_entry_struct entry_struct; int required = 0; parse_opt_str(opt_str, ¶m_list, &arg_type, &required); entry->arg_data = arg_data; entry->description = description; entry->arg_description = arg_description; entry->arg_type = arg_type; entry->required = required; entry->param_names = param_list; cfulist_push(context->option_list, (void *)entry); entry_struct.entry = entry; entry_struct.context = context; cfulist_foreach(param_list, _add_to_option_map, &entry_struct); }
/* Parse a string like Perl's Getopt::Long takes, e.g. "verbose|v!", "file|f=s", "scale:f", "count:i" ! means boolean flag = means required : means optional s means arbitrary string (C string) f means float (double) i means integer (long) */ static void parse_opt_str(const char *opt_str, cfulist_t **param_list, cfuopt_arg_t *type, int *is_required) { cfulist_t *params = cfulist_new(); size_t num_names = 0; char **opt_names = cfustring_c_str_split(opt_str, &num_names, 0, "|", NULL); char *last_opt = NULL; char *pos = NULL; size_t opt_len = 0; cfuopt_arg_t arg_type = cfuopt_arg_invalid; int required = 0; size_t i = 0; if (num_names == 0) { cfulist_destroy(params); free(opt_names); return; } last_opt = opt_names[num_names - 1]; opt_len = strlen(last_opt); if ( (pos = memchr((void *)last_opt, '=', opt_len)) ) { char *tmp = pos; required = 1; tmp++; if (*tmp) { CFUOPT_SET_TYPE(*tmp, arg_type); *pos = '\000'; } else { arg_type = cfuopt_arg_invalid; } } else if ( (pos = memchr((void *)last_opt, ':', opt_len)) ) { char *tmp = pos; required = 0; tmp++; if (*tmp) { CFUOPT_SET_TYPE(*tmp, arg_type); *pos = '\000'; } else { arg_type = cfuopt_arg_invalid; } } else if ( (pos = memchr((void *)last_opt, '!', opt_len)) ) { required = 0; arg_type = cfuopt_arg_bool; *pos = '\000'; } for (i = 0; i < num_names; i++) { cfulist_push(params, opt_names[i]); } free(opt_names); *type = arg_type; *param_list = params; *is_required = required; }
static int _get_help_lines(void *data, size_t data_size, void *arg) { _cfuopt_desc *desc_ds = (_cfuopt_desc *)data; _help_lines_ds *ds = (_help_lines_ds *)arg; char *left_col = NULL; const char *desc = NULL; char *line = NULL; data_size = data_size; left_col = desc_ds->desc; if (!left_col) return 0; desc = desc_ds->entry->description; if (!desc) desc = "test desc"; line = cfustring_sprintf_c_str(ds->fmt, left_col, desc); cfulist_push(ds->list, (void *)line); return 0; }
int cfulist_enqueue(cfulist_t *list, void *data) { return cfulist_push(list, data); }
extern void cfuopt_parse(cfuopt_t *context, int *argc, char ***argv, char **error) { int i = 0; char **args = *argv; int is_long_opt = 0; int is_short_opt = 0; int is_data = 0; int is_end_of_opt = 0; char *parsed_arg = NULL; const char *value = NULL; cfuopt_list_entry_t *entry = NULL; size_t extra_count = 0; error = error; if (!context) return; if (*argc < 1) return; context->progname = cfustring_dup_c_str(args[0]); if (*argc < 2) return; for (i = 1; i < *argc; i++) { char *cur_arg = args[i]; entry = NULL; value = NULL; if (parsed_arg) free(parsed_arg); parsed_arg = NULL; check_arg(cur_arg, &is_long_opt, &is_short_opt, &is_data, &is_end_of_opt, &parsed_arg, &value); if (is_long_opt || is_short_opt) { entry = (cfuopt_list_entry_t *)cfuhash_get(context->option_map, parsed_arg); if (parsed_arg) free(parsed_arg); parsed_arg = NULL; } else if (is_end_of_opt) { if (parsed_arg) free(parsed_arg); parsed_arg = NULL; i++; for (; i < *argc; i++) { cfulist_push(context->extra, args[i]); } break; } else if (is_data) { if (parsed_arg) free(parsed_arg); parsed_arg = NULL; cfulist_push(context->extra, args[i]); continue; } if (!entry) { /* FIXME: return error here if need be */ continue; } switch (entry->arg_type) { case cfuopt_arg_bool: _set_entry_val(entry, "1"); break; case cfuopt_arg_string: case cfuopt_arg_int: case cfuopt_arg_float: if (value) { if (entry->arg_data) { _set_entry_val(entry, value); } } else { i++; if (i >= *argc) break; /* FIXME: set up error msg here */ check_arg(args[i], &is_long_opt, &is_short_opt, &is_data, &is_end_of_opt, &parsed_arg, &value); if (!is_data) { i--; break; /* FIXME: set up error msg here */ } _set_entry_val(entry, parsed_arg); free(parsed_arg); parsed_arg = NULL; } break; case cfuopt_arg_string_array: break; case cfuopt_arg_invalid: /* FIXME: really should produce an error msg here */ break; default: break; } } extra_count = cfulist_num_entries(context->extra); *argc = extra_count + 1; { _update_extra_ds ds; size_t update_count = 0; ds.count = 1; ds.argv = args; update_count = cfulist_foreach(context->extra, _update_extra, (void *)&ds); assert(update_count + 1 == (unsigned)*argc); } }