X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=lsu.c;h=8ccf80d541929194f984759e38d7ffa7998d3c97;hp=de6f2cbcdf16f63149df685b3d7754a71ec6ab25;hb=3622134825eb94882a8e99acc0ee1889fc0169d6;hpb=e072e2a4feb9879f66bc4847a5007cec07b5f5f7 diff --git a/lsu.c b/lsu.c index de6f2cbc..8ccf80d5 100644 --- a/lsu.c +++ b/lsu.c @@ -8,6 +8,8 @@ #include "para.h" #include "error.h" #include "string.h" +#include "lsu.h" +#include "fd.h" static int lsu_lopsub_error(int ret, char **errctx, char **result, unsigned *num_chars) { @@ -136,3 +138,98 @@ int lsu_com_help(bool long_help, const struct lls_parse_result *lpr, *num_chars = n; return 1; } + +/** + * Merge command line options and config file options. + * + * This function parses the options stored in the configuration file and merges + * them with the currently effective options. If the application supports + * config files, it is supposed to call this after the command line options + * have been parsed. If the application also supports config file reloading, + * the function will be called for that purpose. + * + * \param path Config file path, usually the argument to --config-file. + * \param dflt Relative to ~/.paraslash, ignored if path is not NULL. + * \param lpr Value-result pointer. + * \param cmd Passed to lls_parse() and lls_merge(). + * \param suite Needed to tell whether cmd is the supercommand. + * \param flags See enum \ref lsu_merge_cf_flags. + * + * The function does nothing if path is NULL and the default config file does + * not exist, or if path is an empty file. Otherwise, the options of the config + * file are parsed, the parse result is merged with lpr, and the merged parse + * result is returned via lpr. + * + * By default, lpr is freed if the merge was done, but this can be changed by + * including MCF_DONT_FREE flags. + * + * \return Zero if there was nothing to do, one if the config file options were + * merged successfully, negative error code on failure. It is considered an error + * if path is given, but the file does not exist. + */ +int lsu_merge_config_file_options(const char *path, const char *dflt, + struct lls_parse_result **lpr, const struct lls_command *cmd, + const struct lls_suite *suite, unsigned flags) +{ + int ret; + void *map; + size_t sz; + int cf_argc; + char *cf, **cf_argv, *errctx = NULL; + struct lls_parse_result *old_lpr = *lpr, *cf_lpr, *merged_lpr; + const char *subcmd_name; + + if (path) + cf = para_strdup(path); + else { + char *home = para_homedir(); + cf = make_message("%s/.paraslash/%s", home, dflt); + free(home); + } + ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL); + if (ret < 0) { + if (ret == -E_EMPTY) + ret = 0; + else if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) && !path) + ret = 0; + else + PARA_ERROR_LOG("failed to mmap config file %s\n", cf); + goto free_cf; + } + subcmd_name = (lls_cmd(0, suite) == cmd)? NULL : lls_command_name(cmd); + ret = lls(lls_convert_config(map, sz, subcmd_name, &cf_argv, &errctx)); + para_munmap(map, sz); + if (ret < 0) { + PARA_ERROR_LOG("failed to convert config file %s\n", cf); + goto lopsub_error; + } + cf_argc = ret; + ret = lls(lls_parse(cf_argc, cf_argv, cmd, &cf_lpr, &errctx)); + lls_free_argv(cf_argv); + if (ret < 0) { + PARA_ERROR_LOG("failed to parse config file %s\n", cf); + goto lopsub_error; + } + if (flags & MCF_OVERRIDE) + ret = lls(lls_merge(cf_lpr, old_lpr, cmd, &merged_lpr, &errctx)); + else + ret = lls(lls_merge(old_lpr, cf_lpr, cmd, &merged_lpr, &errctx)); + lls_free_parse_result(cf_lpr, cmd); + if (ret < 0) { + PARA_ERROR_LOG("could not merge options in %s\n", cf); + goto lopsub_error; + } + if (!(flags & MCF_DONT_FREE)) + lls_free_parse_result(old_lpr, cmd); + *lpr = merged_lpr; + ret = 1; + goto free_cf; +lopsub_error: + assert(ret < 0); + if (errctx) + PARA_ERROR_LOG("lopsub error: %s\n", errctx); + free(errctx); +free_cf: + free(cf); + return ret; +}