diff --git a/command.c b/command.c index 4b502b3cc9..cd1750ca54 100644 --- a/command.c +++ b/command.c @@ -3018,7 +3018,8 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) break; case MP_CMD_LOADLIST:{ - play_tree_t *e = parse_playlist_file(mpctx->mconfig, cmd->args[0].v.s); + play_tree_t *e = parse_playlist_file(mpctx->mconfig, + bstr(cmd->args[0].v.s)); if (!e) mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "\nUnable to load playlist %s.\n", cmd->args[0].v.s); diff --git a/mplayer.c b/mplayer.c index b0c49fcc14..23a2636989 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1052,7 +1052,7 @@ static int libmpdemux_was_interrupted(struct MPContext *mpctx, int stop_play) static int playtree_add_playlist(struct MPContext *mpctx, play_tree_t* entry) { - play_tree_add_bpf(entry,mpctx->filename); + play_tree_add_bpf(entry, bstr(mpctx->filename)); { if(!entry) { @@ -4191,7 +4191,7 @@ while (opts->player_idle_mode && !mpctx->filename) { // The entry is added to the main playtree after the switch(). break; case MP_CMD_LOADLIST: - entry = parse_playlist_file(mpctx->mconfig, cmd->args[0].v.s); + entry = parse_playlist_file(mpctx->mconfig, bstr(cmd->args[0].v.s)); break; case MP_CMD_QUIT: exit_player_with_rc(mpctx, EXIT_QUIT, (cmd->nargs > 0)? cmd->args[0].v.i : 0); diff --git a/parser-mpcmd.c b/parser-mpcmd.c index 343e9a5a84..112c5fdba8 100644 --- a/parser-mpcmd.c +++ b/parser-mpcmd.c @@ -32,33 +32,12 @@ #include "parser-mpcmd.h" #include "osdep/macosx_finder_args.h" -static int mode = 0; - #define GLOBAL 0 #define LOCAL 1 -#define DROP_LOCAL 2 #define dvd_range(a) (a > 0 && a < 256) -static int is_entry_option(struct m_config *mconfig, char *opt, char *param, - play_tree_t **ret) -{ - *ret = NULL; - - if (strcasecmp(opt, "playlist") == 0) { // We handle playlist here - if (!param) - return M_OPT_MISSING_PARAM; - - *ret = parse_playlist_file(mconfig, param); - if (!*ret) - return -1; - else - return 1; - } - return 0; -} - static inline void add_entry(play_tree_t **last_parentp, play_tree_t **last_entryp, play_tree_t *entry) { @@ -69,16 +48,36 @@ static inline void add_entry(play_tree_t **last_parentp, *last_entryp = entry; } +static bool split_opt(struct bstr *opt, struct bstr *param, bool *old_syntax) +{ + if (!bstr_startswith0(*opt, "-") || opt->len == 1) + return false; + if (bstr_startswith0(*opt, "--")) { + *old_syntax = false; + *opt = bstr_cut(*opt, 2); + *param = bstr(NULL); + int idx = bstrchr(*opt, '='); + if (idx > 0) { + *param = bstr_cut(*opt, idx + 1); + *opt = bstr_splice(*opt, 0, idx); + } + } else { + *old_syntax = true; + *opt = bstr_cut(*opt, 1); + } + return true; +} + + // Parse command line to set up config and playtree play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, char **argv) { - int i, j, start_title = -1, end_title = -1; - char *opt, *splitpos = NULL; - char entbuf[15]; + int mode = 0; bool no_more_opts = false; - int opt_exit = 0; // whether mplayer should exit without playing anything + bool opt_exit = false; // exit immediately after parsing (help options) play_tree_t *last_parent, *last_entry = NULL, *root; + struct bstr orig_opt; assert(config != NULL); assert(argv != NULL); @@ -94,15 +93,16 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, last_parent = root = play_tree_new(); - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { //next: - opt = argv[i]; + struct bstr opt = bstr(argv[i]); + orig_opt = opt; /* check for -- (no more options id.) except --help! */ - if (!strcmp(opt, "--")) { + if (!bstrcmp0(opt, "--")) { no_more_opts = true; continue; } - if ((opt[0] == '{') && (opt[1] == '\0')) { + if (!bstrcmp0(opt, "{")) { play_tree_t *entry = play_tree_new(); mode = LOCAL; if (last_parent->flags & PLAY_TREE_RND) @@ -117,7 +117,7 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, continue; } - if ((opt[0] == '}') && (opt[1] == '\0')) { + if (!bstrcmp0(opt, "}")) { if (!last_parent || !last_parent->parent) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too much }-\n"); goto err_out; @@ -127,101 +127,87 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, continue; } - if ((no_more_opts == 0) && (*opt == '-') && (*(opt + 1) != 0)) { - int tmp = 0; - /* remove trailing '-' */ - opt++; - - mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt); - // We handle here some specific option - // Loop option when it apply to a group - if (strcasecmp(opt, "loop") == 0 && + struct bstr param = bstr(i+1 < argc ? argv[i+1] : NULL); + bool old_syntax; + if (!no_more_opts && split_opt(&opt, ¶m, &old_syntax)) { + // Handle some special arguments outside option parser. + // --loop when it applies to a group of files (per-file is option) + if (bstrcasecmp0(opt, "loop") == 0 && (!last_entry || last_entry->child)) { - int l; - char *end = NULL; - l = (i + 1 < argc) ? strtol(argv[i + 1], &end, 0) : 0; - if (!end || *end != '\0') { + struct bstr rest; + int l = bstrtoll(param, &rest, 0); + if (!param.len || rest.len) { mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "The loop option must be an integer: %s\n", - argv[i + 1]); - tmp = ERR_OUT_OF_RANGE; + "The loop option must be an integer: \"%.*s\"\n", + BSTR_P(param)); + goto print_err; } else { play_tree_t *pt = last_entry ? last_entry : last_parent; l = l <= 0 ? -1 : l; pt->loop = l; - tmp = 1; + i += old_syntax; } - } else if (strcasecmp(opt, "shuffle") == 0) { + } else if (bstrcasecmp0(opt, "shuffle") == 0) { if (last_entry && last_entry->child) last_entry->flags |= PLAY_TREE_RND; else last_parent->flags |= PLAY_TREE_RND; - } else if (strcasecmp(opt, "noshuffle") == 0) { + } else if (bstrcasecmp0(opt, "noshuffle") == 0 || + bstrcasecmp0(opt, "no-shuffle") == 0) { if (last_entry && last_entry->child) last_entry->flags &= ~PLAY_TREE_RND; else last_parent->flags &= ~PLAY_TREE_RND; + } else if (bstrcasecmp0(opt, "playlist") == 0) { + if (param.len <= 0) + goto print_err; + struct play_tree *entry = parse_playlist_file(config, param); + if (!entry) + goto print_err; + add_entry(&last_parent, &last_entry, entry); + if ((last_parent->flags & PLAY_TREE_RND) && entry->child) + entry->flags |= PLAY_TREE_RND; + mode = LOCAL; + i += old_syntax; } else { - const m_option_t *mp_opt = NULL; - play_tree_t *entry = NULL; - - tmp = is_entry_option(config, opt, - (i + 1 < argc) ? argv[i + 1] : NULL, &entry); - if (tmp > 0) { // It's an entry - if (entry) { - add_entry(&last_parent, &last_entry, entry); - if ((last_parent->flags & PLAY_TREE_RND) - && entry->child) - entry->flags |= PLAY_TREE_RND; - mode = LOCAL; - } else if (mode == LOCAL) // Drop params for empty entry - mode = DROP_LOCAL; - } else if (tmp == 0) { // 'normal' options - mp_opt = m_config_get_option(config, bstr(opt)); - if (mp_opt != NULL) { // Option exist - if (mode == GLOBAL || (mp_opt->flags & M_OPT_GLOBAL)) - tmp = (i + 1 < argc) - ? m_config_set_option0(config, opt, argv[i + 1], - true) - : m_config_set_option0(config, opt, NULL, false); - else { - tmp = m_config_check_option0(config, opt, - (i + 1 < argc) ? argv[i + 1] : NULL, true); - if (tmp >= 0 && mode != DROP_LOCAL) { - play_tree_t *pt = - last_entry ? last_entry : last_parent; - play_tree_set_param(pt, opt, argv[i + 1]); - } - } - } else { - tmp = M_OPT_UNKNOWN; - mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, - "Unknown option on the command line: -%s\n", - opt); + // "normal" options + const struct m_option *mp_opt; + mp_opt = m_config_get_option(config, opt); + if (!mp_opt) { + mp_tmsg(MSGT_CFGPARSER, MSGL_ERR, + "Unknown option on the command line: --%.*s\n", + BSTR_P(opt)); + goto print_err; + } + int r; + if (mode == GLOBAL || (mp_opt->flags & M_OPT_GLOBAL)) { + r = m_config_set_option(config, opt, param, old_syntax); + } else { + r = m_config_check_option(config, opt, param, old_syntax); + if (r >= 0) { + play_tree_t *pt = last_entry ? last_entry : last_parent; + play_tree_set_param(pt, opt, param); } } + if (r <= M_OPT_EXIT) { + opt_exit = true; + r = M_OPT_EXIT - r; + } else if (r < 0) + goto print_err; + if (old_syntax) + i += r; } - - if (tmp <= M_OPT_EXIT) { - opt_exit = 1; - tmp = M_OPT_EXIT - tmp; - } else if (tmp < 0) { - mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, - "Error parsing option on the command line: -%s\n", - opt); - goto err_out; - } - i += tmp; - } else { /* filename */ + } else { /* filename */ int is_dvdnav = strstr(argv[i], "dvdnav://") != NULL; play_tree_t *entry = play_tree_new(); mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Adding file %s\n", argv[i]); // expand DVD filename entries like dvd://1-3 into component titles if (strstr(argv[i], "dvd://") != NULL || is_dvdnav) { int offset = is_dvdnav ? 9 : 6; - splitpos = strstr(argv[i] + offset, "-"); + char *splitpos = strstr(argv[i] + offset, "-"); if (splitpos != NULL) { - start_title = strtol(argv[i] + offset, NULL, 10); + int start_title = strtol(argv[i] + offset, NULL, 10); + int end_title; //entries like dvd://-2 imply start at title 1 if (start_title < 0) { end_title = abs(start_title); @@ -231,9 +217,10 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, if (dvd_range(start_title) && dvd_range(end_title) && (start_title < end_title)) { - for (j = start_title; j <= end_title; j++) { + for (int j = start_title; j <= end_title; j++) { if (j != start_title) entry = play_tree_new(); + char entbuf[15]; snprintf(entbuf, sizeof(entbuf), is_dvdnav ? "dvdnav://%d" : "dvd://%d", j); play_tree_add_file(entry, entbuf); @@ -263,6 +250,10 @@ play_tree_t *m_config_parse_mp_command_line(m_config_t *config, int argc, mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Missing }- ?\n"); return root; +print_err: + mp_tmsg(MSGT_CFGPARSER, MSGL_FATAL, + "Error parsing option on the command line: %.*s\n", + BSTR_P(orig_opt)); err_out: play_tree_free(root, 1); return NULL; @@ -286,25 +277,22 @@ int m_config_preparse_command_line(m_config_t *config, int argc, char **argv) config->mode = M_COMMAND_LINE_PRE_PARSE; for (int i = 1 ; i < argc ; i++) { - const struct m_option *opt; - char *arg = argv[i]; - // Ignore non option - if (arg[0] != '-' || arg[1] == 0) continue; + struct bstr opt = bstr(argv[i]); // No more options after -- - if (!strcmp(arg, "--")) + if (!bstrcmp0(opt, "--")) break; - arg++; - - opt = m_config_get_option(config, bstr(arg)); - // Ignore invalid option - if (!opt) + struct bstr param = bstr(i+1 < argc ? argv[i+1] : NULL); + bool old_syntax; + if (!split_opt(&opt, ¶m, &old_syntax)) + continue; // Ignore non-option arguments + // Ignore invalid options + if (!m_config_get_option(config, opt)) continue; // Set, non-pre-parse options will be ignored - int r = m_config_set_option0(config, arg, i+1 < argc ? argv[i+1] : NULL, - true); + int r = m_config_set_option(config, opt, param, old_syntax); if (r < 0) ret = r; - else + else if (old_syntax) i += r; } diff --git a/playtree.c b/playtree.c index abd9b35e0f..0e3295c24c 100644 --- a/playtree.c +++ b/playtree.c @@ -346,7 +346,7 @@ play_tree_remove_file(play_tree_t* pt,const char* file) { } void -play_tree_set_param(play_tree_t* pt, const char* name, const char* val) { +play_tree_set_param(play_tree_t* pt, struct bstr name, struct bstr val) { int n = 0; #ifdef MP_DEBUG @@ -358,8 +358,8 @@ play_tree_set_param(play_tree_t* pt, const char* name, const char* val) { for ( ; pt->params[n].name != NULL ; n++ ) { } pt->params = talloc_realloc(NULL, pt->params, struct play_tree_param, n + 2); - pt->params[n].name = talloc_strdup(pt->params, name); - pt->params[n].value = val != NULL ? talloc_strdup(pt->params, val) : NULL; + pt->params[n].name = bstrdup0(pt->params, name); + pt->params[n].value = bstrdup0(pt->params, val); memset(&pt->params[n+1],0,sizeof(play_tree_param_t)); return; @@ -410,7 +410,7 @@ play_tree_set_params_from(play_tree_t* dest,play_tree_t* src) { return; for(i = 0; src->params[i].name != NULL ; i++) - play_tree_set_param(dest,src->params[i].name,src->params[i].value); + play_tree_set_param(dest, bstr(src->params[i].name), bstr(src->params[i].value)); if(src->flags & PLAY_TREE_RND) // pass the random flag too dest->flags |= PLAY_TREE_RND; diff --git a/playtree.h b/playtree.h index 380f989133..7af1518fd0 100644 --- a/playtree.h +++ b/playtree.h @@ -19,6 +19,8 @@ #ifndef MPLAYER_PLAYTREE_H #define MPLAYER_PLAYTREE_H +#include "bstr.h" + /// \file /// \ingroup Playtree @@ -188,7 +190,7 @@ play_tree_remove_file(play_tree_t* pt,const char* file); /// Add a config paramter to an item. void -play_tree_set_param(play_tree_t* pt, const char* name, const char* val); +play_tree_set_param(play_tree_t* pt, struct bstr name, struct bstr val); /// Remove a config parameter from an item. int @@ -257,7 +259,7 @@ play_tree_cleanup(play_tree_t* pt); /** \ingroup PlaytreeParser */ play_tree_t* -parse_playlist_file(struct m_config *mconfig, char* file); +parse_playlist_file(struct m_config *mconfig, struct bstr file); /// \defgroup PtAPI Playtree highlevel API /// \ingroup Playtree diff --git a/playtreeparser.c b/playtreeparser.c index 777af83634..14220274de 100644 --- a/playtreeparser.c +++ b/playtreeparser.c @@ -31,6 +31,8 @@ #include #include #include + +#include "talloc.h" #include "asxparser.h" #include "m_config.h" #include "playtree.h" @@ -355,7 +357,7 @@ parse_pls(play_tree_parser_t* p) { entry = play_tree_new(); play_tree_add_file(entry,entries[num].file); if (entries[num].length) - play_tree_set_param(entry, "endpos", entries[num].length); + play_tree_set_param(entry, bstr("endpos"), bstr(entries[num].length)); free(entries[num].file); if(list) play_tree_append_entry(last_entry,entry); @@ -853,13 +855,13 @@ play_tree_add_basepath(play_tree_t* pt, char* bp) { } // Wrapper for play_tree_add_basepath (add base path from file) -void play_tree_add_bpf(play_tree_t* pt, char* filename) +void play_tree_add_bpf(play_tree_t *pt, struct bstr filename) { char *ls, *file; - if (pt && filename) + if (pt) { - file = strdup(filename); + file = bstrdup0(NULL, filename); if (file) { ls = strrchr(file,'/'); @@ -868,25 +870,30 @@ void play_tree_add_bpf(play_tree_t* pt, char* filename) ls[1] = '\0'; play_tree_add_basepath(pt,file); } - free(file); + talloc_free(file); } } } play_tree_t* -parse_playlist_file(struct m_config *mconfig, char* file) { +parse_playlist_file(struct m_config *mconfig, struct bstr file) { stream_t *stream; play_tree_t* ret; int f=DEMUXER_TYPE_PLAYLIST; - stream = open_stream(file,0,&f); + char *file0 = bstrdup0(NULL, file); + stream = open_stream(file0, 0, &f); + talloc_free(file0); if(!stream) { - mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Error while opening playlist file %s: %s\n",file,strerror(errno)); + mp_msg(MSGT_PLAYTREE,MSGL_ERR, + "Error while opening playlist file %.*s: %s\n", + BSTR_P(file), strerror(errno)); return NULL; } - mp_msg(MSGT_PLAYTREE,MSGL_V,"Parsing playlist file %s...\n",file); + mp_msg(MSGT_PLAYTREE, MSGL_V, + "Parsing playlist file %.*s...\n", BSTR_P(file)); ret = parse_playtree(stream, mconfig, 1); free_stream(stream); diff --git a/playtreeparser.h b/playtreeparser.h index a3d729fdb3..a774bb9e4a 100644 --- a/playtreeparser.h +++ b/playtreeparser.h @@ -20,6 +20,7 @@ #define MPLAYER_PLAYTREEPARSER_H #include "playtree.h" +#include "bstr.h" /// \defgroup PlaytreeParser Playtree parser /// \ingroup Playtree @@ -65,7 +66,7 @@ play_tree_parser_get_play_tree(play_tree_parser_t* p, int forced); /// Wrapper for play_tree_add_basepath (add base path from file). void -play_tree_add_bpf(play_tree_t* pt, char* filename); +play_tree_add_bpf(play_tree_t* pt, struct bstr filename); ///@}