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; }
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); }
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; }
char * cfulist_join(cfulist_t *list, const char *delimiter) { _join_foreach_struct *arg = calloc(1, sizeof(_join_foreach_struct)); char *str = NULL; arg->delimiter = delimiter; arg->string = cfustring_new(); cfulist_foreach(list, _join_foreach_fn, (void *)arg); str = cfustring_get_buffer_copy(arg->string); cfustring_destroy(arg->string); free(arg); return str; }
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); } }