Пример #1
0
// Returns true if more args, false if all parsed or an error occurred.
static bool split_opt(struct parse_state *p)
{
    int r = split_opt_silent(p);
    if (r >= 0)
        return r == 0;
    p->error = true;

    MP_FATAL(p->config, "Error parsing command line option '%.*s': %s\n",
             BSTR_P(p->arg), m_option_strerror(r));
    return false;
}
Пример #2
0
// Returns true if more args, false if all parsed or an error occurred.
static bool split_opt(struct parse_state *p)
{
    int r = split_opt_silent(p);
    if (r >= 0)
        return r == 0;
    p->error = true;

    mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL,
            "Error parsing commandline option %.*s: %s\n",
            BSTR_P(p->arg), m_option_strerror(r));
    return false;
}
Пример #3
0
/** \param config The config object.
 *  \param conffile Path to the config file.
 *  \return 1 on sucess, -1 on error, 0 if file not accessible.
 */
int m_config_parse_config_file(m_config_t *config, const char *conffile)
{
#define PRINT_LINENUM   mp_msg(MSGT_CFGPARSER, MSGL_ERR, "%s:%d: ", conffile, line_num)
#define MAX_LINE_LEN    10000
#define MAX_OPT_LEN     1000
#define MAX_PARAM_LEN   1500
    FILE *fp = NULL;
    char *line = NULL;
    char opt[MAX_OPT_LEN + 1];
    char param[MAX_PARAM_LEN + 1];
    char c;             /* for the "" and '' check */
    int tmp;
    int line_num = 0;
    int line_pos;       /* line pos */
    int opt_pos;        /* opt pos */
    int param_pos;      /* param pos */
    int ret = 1;
    int errors = 0;
    m_profile_t *profile = NULL;

    mp_msg(MSGT_CFGPARSER, MSGL_V, "Reading config file %s", conffile);

    if (recursion_depth > MAX_RECURSION_DEPTH) {
        mp_msg(MSGT_CFGPARSER, MSGL_ERR,
               ": too deep 'include'. check your configfiles\n");
        ret = -1;
        goto out;
    }

    if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
        mp_msg(MSGT_CFGPARSER, MSGL_FATAL,
               "\ncan't get memory for 'line': %s", strerror(errno));
        ret = -1;
        goto out;
    } else

        mp_msg(MSGT_CFGPARSER, MSGL_V, "\n");

    if ((fp = fopen(conffile, "r")) == NULL) {
        mp_msg(MSGT_CFGPARSER, MSGL_V, ": %s\n", strerror(errno));
        ret = 0;
        goto out;
    }

    while (fgets(line, MAX_LINE_LEN, fp)) {
        if (errors >= 16) {
            mp_msg(MSGT_CFGPARSER, MSGL_FATAL, "too many errors\n");
            goto out;
        }

        line_num++;
        line_pos = 0;

        /* skip whitespaces */
        while (isspace(line[line_pos]))
            ++line_pos;

        /* EOL / comment */
        if (line[line_pos] == '\0' || line[line_pos] == '#')
            continue;

        /* read option. */
        for (opt_pos = 0; isprint(line[line_pos]) &&
             line[line_pos] != ' ' &&
             line[line_pos] != '#' &&
             line[line_pos] != '='; /* NOTHING */) {
            opt[opt_pos++] = line[line_pos++];
            if (opt_pos >= MAX_OPT_LEN) {
                PRINT_LINENUM;
                mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too long option\n");
                errors++;
                ret = -1;
                goto nextline;
            }
        }
        if (opt_pos == 0) {
            PRINT_LINENUM;
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parse error\n");
            ret = -1;
            errors++;
            continue;
        }
        opt[opt_pos] = '\0';

        /* Profile declaration */
        if (opt_pos > 2 && opt[0] == '[' && opt[opt_pos - 1] == ']') {
            opt[opt_pos - 1] = '\0';
            if (strcmp(opt + 1, "default"))
                profile = m_config_add_profile(config, opt + 1);
            else
                profile = NULL;
            continue;
        }

        /* skip whitespaces */
        while (isspace(line[line_pos]))
            ++line_pos;

        param_pos = 0;
        bool param_set = false;

        /* check '=' */
        if (line[line_pos] == '=') {
            line_pos++;
            param_set = true;

            /* whitespaces... */
            while (isspace(line[line_pos]))
                ++line_pos;

            /* read the parameter */
            if (line[line_pos] == '"' || line[line_pos] == '\'') {
                c = line[line_pos];
                ++line_pos;
                for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
                    param[param_pos++] = line[line_pos++];
                    if (param_pos >= MAX_PARAM_LEN) {
                        PRINT_LINENUM;
                        mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                               "option %s has a too long parameter\n", opt);
                        ret = -1;
                        errors++;
                        goto nextline;
                    }
                }
                line_pos++;                 /* skip the closing " or ' */
            } else {
                for (param_pos = 0; isprint(line[line_pos])
                        && !isspace(line[line_pos])
                        && line[line_pos] != '#'; /* NOTHING */) {
                    param[param_pos++] = line[line_pos++];
                    if (param_pos >= MAX_PARAM_LEN) {
                        PRINT_LINENUM;
                        mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too long parameter\n");
                        ret = -1;
                        errors++;
                        goto nextline;
                    }
                }
            }

            while (isspace(line[line_pos]))
                ++line_pos;
        }
        param[param_pos] = '\0';

        /* EOL / comment */
        if (line[line_pos] != '\0' && line[line_pos] != '#') {
            PRINT_LINENUM;
            mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                   "extra characters: %s\n", line + line_pos);
            ret = -1;
        }

        bstr bopt = bstr0(opt);
        bstr bparam = bstr0(param);

        if (profile && bstr_equals0(bopt, "profile-desc")) {
            m_profile_set_desc(profile, param);
            goto nextline;
        }

        tmp = m_config_option_requires_param(config, bopt);
        if (tmp > 0 && !param_set)
            tmp = M_OPT_MISSING_PARAM;
        if (tmp < 0) {
            PRINT_LINENUM;
            mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                   "error parsing option %s=%s: %s\n",
                   opt, param, m_option_strerror(tmp));
            continue;
        }

        if (profile) {
            tmp = m_config_set_profile_option(config, profile, bopt, bparam);
        } else {
            tmp = m_config_set_option_ext(config, bopt, bparam,
                                          M_SETOPT_FROM_CONFIG_FILE);
        }
        if (tmp < 0) {
            PRINT_LINENUM;
            mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                   "setting option %s='%s' failed.\n", opt, param);
            continue;
            /* break */
        }
nextline:
        ;
    }

out:
    free(line);
    if (fp)
        fclose(fp);
    --recursion_depth;
    if (ret < 0) {
        mp_msg(MSGT_CFGPARSER, MSGL_FATAL, "Error loading config file %s.\n",
               conffile);
    }
    return ret;
}
Пример #4
0
bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files,
                                    int argc, char **argv)
{
    int mode = 0;
    struct playlist_entry *local_start = NULL;
    bool shuffle = false;

    int local_params_count = 0;
    struct playlist_param *local_params = 0;

    assert(config != NULL);
    assert(!config->file_local_mode);

    config->mode = M_COMMAND_LINE;
    mode = GLOBAL;
#ifdef CONFIG_MACOSX_FINDER
    if (macosx_finder_args(config, files, argc, argv))
        return true;
#endif

    struct parse_state p = {config, argc, argv};
    while (split_opt(&p)) {
        if (p.mp_opt) {
            int r;
            if (mode == GLOBAL && !(p.mp_opt->flags & M_OPT_PRE_PARSE)) {
                r = m_config_set_option(config, p.arg, p.param);
            } else {
                r = m_config_check_option(config, p.arg, p.param);
            }
            if (r <= M_OPT_EXIT)
                goto err_out;
            if (r < 0) {
                char *msg = m_option_strerror(r);
                if (!msg)
                    goto print_err;
                mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL,
                        "Error parsing commandline option %.*s: %s\n",
                        BSTR_P(p.arg), msg);
                goto err_out;
            }

            // Handle some special arguments outside option parser.

            if (!bstrcmp0(p.arg, "{")) {
                if (mode != GLOBAL) {
                    mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                           "'--{' can not be nested.\n");
                    goto err_out;
                }
                mode = LOCAL;
                // Needed for option checking.
                m_config_enter_file_local(config);
                assert(!local_start);
                local_start = files->last;
                continue;
            }

            if (!bstrcmp0(p.arg, "}")) {
                if (mode != LOCAL) {
                    mp_msg(MSGT_CFGPARSER, MSGL_ERR,
                           "Too many closing '--}'.\n");
                    goto err_out;
                }
                if (local_params_count) {
                    // The files added between '{' and '}' are the entries from
                    // the entry _after_ local_start, until the end of the list.
                    // If local_start is NULL, the list was empty on '{', and we
                    // want all files in the list.
                    struct playlist_entry *cur
                        = local_start ? local_start->next : files->first;
                    if (!cur)
                        mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Ignored options!\n");
                    while (cur) {
                        playlist_entry_add_params(cur, local_params,
                                                local_params_count);
                        cur = cur->next;
                    }
                }
                local_params_count = 0;
                mode = GLOBAL;
                m_config_leave_file_local(config);
                local_start = NULL;
                shuffle = false;
                continue;
            }

            if (bstrcmp0(p.arg, "shuffle") == 0) {
                shuffle = parse_flag(p.arg, p.param);
                continue;
            }

            if (bstrcmp0(p.arg, "playlist") == 0) {
                // append the playlist to the local args
                char *param0 = bstrdup0(NULL, p.param);
                struct playlist *pl = playlist_parse_file(param0);
                talloc_free(param0);
                if (!pl)
                    goto print_err;
                playlist_transfer_entries(files, pl);
                talloc_free(pl);
                continue;
            }

            if (mode == LOCAL) {
                MP_TARRAY_APPEND(NULL, local_params, local_params_count,
                                 (struct playlist_param) {p.arg, p.param});
            }
Пример #5
0
// Load options and profiles from from a config file.
//  conffile: path to the config file
//  initial_section: default section where to add normal options
//  flags: M_SETOPT_* bits
//  returns: 1 on sucess, -1 on error, 0 if file not accessible.
int m_config_parse_config_file(m_config_t *config, const char *conffile,
                               char *initial_section, int flags)
{
#define PRINT_LINENUM   MP_ERR(config, "%s:%d: ", conffile, line_num)
#define MAX_LINE_LEN    10000
#define MAX_OPT_LEN     1000
#define MAX_PARAM_LEN   1500
    FILE *fp = NULL;
    char *line = NULL;
    char opt[MAX_OPT_LEN + 1];
    char param[MAX_PARAM_LEN + 1];
    char c;             /* for the "" and '' check */
    int tmp;
    int line_num = 0;
    int line_pos;       /* line pos */
    int opt_pos;        /* opt pos */
    int param_pos;      /* param pos */
    int ret = 1;
    int errors = 0;
    m_profile_t *profile = m_config_add_profile(config, initial_section);

    flags = flags | M_SETOPT_FROM_CONFIG_FILE;

    MP_VERBOSE(config, "Reading config file %s\n", conffile);

    if (config->recursion_depth > MAX_RECURSION_DEPTH) {
        MP_ERR(config, "Maximum 'include' nesting depth exceeded.\n");
        ret = -1;
        goto out;
    }

    if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
        ret = -1;
        goto out;
    } else

        MP_VERBOSE(config, "\n");

    if ((fp = fopen(conffile, "r")) == NULL) {
        MP_VERBOSE(config, "Can't open config file: %s\n", strerror(errno));
        ret = 0;
        goto out;
    }

    while (fgets(line, MAX_LINE_LEN, fp)) {
        if (errors >= 16) {
            MP_FATAL(config, "too many errors\n");
            goto out;
        }

        line_num++;
        line_pos = 0;

        /* skip BOM */
        if (strncmp(line, "\xEF\xBB\xBF", 3) == 0)
            line_pos += 3;

        /* skip whitespaces */
        while (mp_isspace(line[line_pos]))
            ++line_pos;

        /* EOL / comment */
        if (line[line_pos] == '\0' || line[line_pos] == '#')
            continue;

        /* read option. */
        for (opt_pos = 0; mp_isprint(line[line_pos]) &&
             line[line_pos] != ' ' &&
             line[line_pos] != '#' &&
             line[line_pos] != '='; /* NOTHING */) {
            opt[opt_pos++] = line[line_pos++];
            if (opt_pos >= MAX_OPT_LEN) {
                PRINT_LINENUM;
                MP_ERR(config, "option name too long\n");
                errors++;
                ret = -1;
                goto nextline;
            }
        }
        if (opt_pos == 0) {
            PRINT_LINENUM;
            MP_ERR(config, "parse error\n");
            ret = -1;
            errors++;
            continue;
        }
        opt[opt_pos] = '\0';

        /* Profile declaration */
        if (opt_pos > 2 && opt[0] == '[' && opt[opt_pos - 1] == ']') {
            opt[opt_pos - 1] = '\0';
            profile = m_config_add_profile(config, opt + 1);
            continue;
        }

        /* skip whitespaces */
        while (mp_isspace(line[line_pos]))
            ++line_pos;

        param_pos = 0;
        bool param_set = false;

        /* check '=' */
        if (line[line_pos] == '=') {
            line_pos++;
            param_set = true;

            /* whitespaces... */
            while (mp_isspace(line[line_pos]))
                ++line_pos;

            /* read the parameter */
            if (line[line_pos] == '"' || line[line_pos] == '\'') {
                c = line[line_pos];
                ++line_pos;
                for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
                    param[param_pos++] = line[line_pos++];
                    if (param_pos >= MAX_PARAM_LEN) {
                        PRINT_LINENUM;
                        MP_ERR(config, "option %s has a too long parameter\n", opt);
                        ret = -1;
                        errors++;
                        goto nextline;
                    }
                }
                line_pos++;                 /* skip the closing " or ' */
                goto param_done;
            }

            if (line[line_pos] == '%') {
                char *start = &line[line_pos + 1];
                char *end = start;
                unsigned long len = strtoul(start, &end, 10);
                if (start != end && end[0] == '%') {
                    if (len >= MAX_PARAM_LEN - 1 ||
                        strlen(end + 1) < len)
                    {
                        PRINT_LINENUM;
                        MP_ERR(config, "bogus %% length\n");
                        ret = -1;
                        errors++;
                        goto nextline;
                    }
                    param_pos = snprintf(param, sizeof(param), "%.*s",
                                         (int)len, end + 1);
                    line_pos += 1 + (end - start) + 1 + len;
                    goto param_done;
                }
            }

            for (param_pos = 0; mp_isprint(line[line_pos])
                    && !mp_isspace(line[line_pos])
                    && line[line_pos] != '#'; /* NOTHING */) {
                param[param_pos++] = line[line_pos++];
                if (param_pos >= MAX_PARAM_LEN) {
                    PRINT_LINENUM;
                    MP_ERR(config, "too long parameter\n");
                    ret = -1;
                    errors++;
                    goto nextline;
                }
            }

        param_done:

            while (mp_isspace(line[line_pos]))
                ++line_pos;
        }
        param[param_pos] = '\0';

        /* EOL / comment */
        if (line[line_pos] != '\0' && line[line_pos] != '#') {
            PRINT_LINENUM;
            MP_ERR(config, "extra characters: %s\n", line + line_pos);
            ret = -1;
        }

        bstr bopt = bstr0(opt);
        bstr bparam = bstr0(param);

        if (bopt.len >= 3)
            bstr_eatstart0(&bopt, "--");

        if (profile && bstr_equals0(bopt, "profile-desc")) {
            m_profile_set_desc(profile, bparam);
            goto nextline;
        }

        bool need_param = m_config_option_requires_param(config, bopt) > 0;
        if (need_param && !param_set) {
            PRINT_LINENUM;
            MP_ERR(config, "error parsing option %.*s=%.*s: %s\n",
                   BSTR_P(bopt), BSTR_P(bparam),
                   m_option_strerror(M_OPT_MISSING_PARAM));
            continue;
        }

        if (profile) {
            tmp = m_config_set_profile_option(config, profile, bopt, bparam);
        } else {
            tmp = m_config_set_option_ext(config, bopt, bparam, flags);
        }
        if (tmp < 0) {
            PRINT_LINENUM;
            MP_ERR(config, "setting option %.*s='%.*s' failed.\n",
                   BSTR_P(bopt), BSTR_P(bparam));
            continue;
            /* break */
        }
nextline:
        ;
    }

out:
    free(line);
    if (fp)
        fclose(fp);
    config->recursion_depth -= 1;
    if (ret < 0) {
        MP_FATAL(config, "Error loading config file %s.\n",
               conffile);
    }
    return ret;
}