extern cfuopt_t * cfuopt_new() { cfuopt_t *context = (cfuopt_t *)calloc(1, sizeof(cfuopt_t)); context->option_list = cfulist_new(); context->option_map = cfuhash_new(); context->extra = cfulist_new(); return context; }
extern char * cfuopt_get_help_str(cfuopt_t *context) { cfulist_t *desc_list = NULL; size_t max_width = 0; char *fmt = NULL; _help_lines_ds ds; char *help_str = NULL; max_width = _find_longest_help_desc(context, &desc_list); fmt = cfustring_sprintf_c_str(" %%-%us %%s\n", max_width); ds.fmt = fmt; ds.list = cfulist_new(); ds.desc_list = desc_list; cfulist_foreach(desc_list, _get_help_lines, (void *)&ds); help_str = cfulist_join(ds.list, "\n"); cfulist_destroy_with_free_fn(ds.list, _list_simple_free_fn); cfulist_destroy_with_free_fn(desc_list, _desc_list_free); free(fmt); return help_str; }
/* 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; }
cfulist_t * cfulist_map(cfulist_t *list, cfulist_map_fn_t map_fn, void *arg) { cfulist_t *new_list = cfulist_new(); _cfulist_map_ds ds; ds.list = new_list; ds.arg = arg; ds.map_fn = map_fn; cfulist_foreach(list, _cfulist_map_foreach, (void *)&ds); return new_list; }
static size_t _find_longest_help_desc(cfuopt_t *context, cfulist_t **desc_list) { _find_foreach_ds ds; ds.max_size = 0; ds.desc_list = cfulist_new(); cfulist_foreach(context->option_list, _find_foreach_fn, (void *)&ds); *desc_list = ds.desc_list; return ds.max_size; }
cfulist_t * cfulist_new_with_free_fn(cfulist_free_fn_t free_fn) { cfulist_t *list = cfulist_new(); list->free_fn = free_fn; return list; }