2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "parser-mpcmd.h"
33 #include "osdep/macosx_finder_args.h"
38 #define dvd_range(a) (a > 0 && a < 256)
41 static inline void add_entry(play_tree_t
**last_parentp
,
42 play_tree_t
**last_entryp
, play_tree_t
*entry
)
44 if (*last_entryp
== NULL
)
45 play_tree_set_child(*last_parentp
, entry
);
47 play_tree_append_entry(*last_entryp
, entry
);
51 static bool split_opt(struct bstr
*opt
, struct bstr
*param
, bool *old_syntax
)
53 if (!bstr_startswith0(*opt
, "-") || opt
->len
== 1)
55 if (bstr_startswith0(*opt
, "--")) {
57 *opt
= bstr_cut(*opt
, 2);
59 int idx
= bstrchr(*opt
, '=');
61 *param
= bstr_cut(*opt
, idx
+ 1);
62 *opt
= bstr_splice(*opt
, 0, idx
);
66 *opt
= bstr_cut(*opt
, 1);
71 static int map_to_option(struct m_config
*config
, bool old_syntax
,
72 const struct m_option
**mp_opt
,
73 struct bstr
*optname
, struct bstr
*param
)
76 mp_opt
= &(const struct m_option
*){0};
77 *mp_opt
= m_config_get_option(config
, *optname
);
80 if (!bstr_startswith0(*optname
, "no-"))
82 struct bstr s
= bstr_cut(*optname
, 3);
83 *mp_opt
= m_config_get_option(config
, s
);
84 if (!*mp_opt
|| (*mp_opt
)->type
!= &m_option_type_flag
)
95 // Parse command line to set up config and playtree
96 play_tree_t
*m_config_parse_mp_command_line(m_config_t
*config
, int argc
,
100 bool no_more_opts
= false;
101 bool opt_exit
= false; // exit immediately after parsing (help options)
102 play_tree_t
*last_parent
, *last_entry
= NULL
, *root
;
103 struct bstr orig_opt
;
105 assert(config
!= NULL
);
106 assert(argv
!= NULL
);
109 config
->mode
= M_COMMAND_LINE
;
111 #ifdef CONFIG_MACOSX_FINDER
112 root
= macosx_finder_args(config
, argc
, argv
);
117 last_parent
= root
= play_tree_new();
119 for (int i
= 1; i
< argc
; i
++) {
121 struct bstr opt
= bstr(argv
[i
]);
123 /* check for -- (no more options id.) except --help! */
124 if (!bstrcmp0(opt
, "--")) {
128 if (!bstrcmp0(opt
, "{")) {
129 play_tree_t
*entry
= play_tree_new();
131 if (last_parent
->flags
& PLAY_TREE_RND
)
132 entry
->flags
|= PLAY_TREE_RND
;
133 if (last_entry
== NULL
)
134 play_tree_set_child(last_parent
, entry
);
136 play_tree_append_entry(last_entry
, entry
);
143 if (!bstrcmp0(opt
, "}")) {
144 if (!last_parent
|| !last_parent
->parent
) {
145 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "too much }-\n");
148 last_entry
= last_parent
;
149 last_parent
= last_entry
->parent
;
153 struct bstr param
= bstr(i
+1 < argc
? argv
[i
+1] : NULL
);
155 if (!no_more_opts
&& split_opt(&opt
, ¶m
, &old_syntax
)) {
156 // Handle some special arguments outside option parser.
157 // --loop when it applies to a group of files (per-file is option)
158 if (bstrcasecmp0(opt
, "loop") == 0 &&
159 (!last_entry
|| last_entry
->child
)) {
161 int l
= bstrtoll(param
, &rest
, 0);
162 if (!param
.len
|| rest
.len
) {
163 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
164 "The loop option must be an integer: \"%.*s\"\n",
168 play_tree_t
*pt
= last_entry
? last_entry
: last_parent
;
173 } else if (bstrcasecmp0(opt
, "shuffle") == 0) {
174 if (last_entry
&& last_entry
->child
)
175 last_entry
->flags
|= PLAY_TREE_RND
;
177 last_parent
->flags
|= PLAY_TREE_RND
;
178 } else if (bstrcasecmp0(opt
, "noshuffle") == 0 ||
179 bstrcasecmp0(opt
, "no-shuffle") == 0) {
180 if (last_entry
&& last_entry
->child
)
181 last_entry
->flags
&= ~PLAY_TREE_RND
;
183 last_parent
->flags
&= ~PLAY_TREE_RND
;
184 } else if (bstrcasecmp0(opt
, "playlist") == 0) {
187 struct play_tree
*entry
= parse_playlist_file(config
, param
);
190 add_entry(&last_parent
, &last_entry
, entry
);
191 if ((last_parent
->flags
& PLAY_TREE_RND
) && entry
->child
)
192 entry
->flags
|= PLAY_TREE_RND
;
197 const struct m_option
*mp_opt
;
198 int ok
= map_to_option(config
, old_syntax
, &mp_opt
, &opt
,
202 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
203 "Option --%.*s can't be used with single-dash "
204 "syntax\n", BSTR_P(opt
));
206 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
207 "A --no-* option can't take parameters: "
208 "--%.*s=%.*s\n", BSTR_P(opt
), BSTR_P(param
));
210 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
211 "Unknown option on the command line: --%.*s\n",
216 if (mode
== GLOBAL
|| (mp_opt
->flags
& M_OPT_GLOBAL
)) {
217 r
= m_config_set_option(config
, opt
, param
, old_syntax
);
219 r
= m_config_check_option(config
, opt
, param
, old_syntax
);
221 play_tree_t
*pt
= last_entry
? last_entry
: last_parent
;
223 param
= bstr(NULL
); // for old_syntax case
224 play_tree_set_param(pt
, opt
, param
);
227 if (r
<= M_OPT_EXIT
) {
231 char *msg
= m_option_strerror(r
);
234 mp_tmsg(MSGT_CFGPARSER
, MSGL_FATAL
,
235 "Error parsing commandline option \"%.*s\": %s\n",
236 BSTR_P(orig_opt
), msg
);
242 } else { /* filename */
243 int is_dvdnav
= strstr(argv
[i
], "dvdnav://") != NULL
;
244 play_tree_t
*entry
= play_tree_new();
245 mp_msg(MSGT_CFGPARSER
, MSGL_DBG2
, "Adding file %s\n", argv
[i
]);
246 // expand DVD filename entries like dvd://1-3 into component titles
247 if (strstr(argv
[i
], "dvd://") != NULL
|| is_dvdnav
) {
248 int offset
= is_dvdnav
? 9 : 6;
249 char *splitpos
= strstr(argv
[i
] + offset
, "-");
250 if (splitpos
!= NULL
) {
251 int start_title
= strtol(argv
[i
] + offset
, NULL
, 10);
253 //entries like dvd://-2 imply start at title 1
254 if (start_title
< 0) {
255 end_title
= abs(start_title
);
258 end_title
= strtol(splitpos
+ 1, NULL
, 10);
260 if (dvd_range(start_title
) && dvd_range(end_title
)
261 && (start_title
< end_title
)) {
262 for (int j
= start_title
; j
<= end_title
; j
++) {
263 if (j
!= start_title
)
264 entry
= play_tree_new();
266 snprintf(entbuf
, sizeof(entbuf
),
267 is_dvdnav
? "dvdnav://%d" : "dvd://%d", j
);
268 play_tree_add_file(entry
, entbuf
);
269 add_entry(&last_parent
, &last_entry
, entry
);
273 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
274 "Invalid play entry %s\n", argv
[i
]);
276 } else // dvd:// or dvd://x entry
277 play_tree_add_file(entry
, argv
[i
]);
279 play_tree_add_file(entry
, argv
[i
]);
281 // Lock stdin if it will be used as input
282 if (strcasecmp(argv
[i
], "-") == 0)
283 m_config_set_option0(config
, "consolecontrols", "no", false);
284 add_entry(&last_parent
, &last_entry
, entry
);
285 mode
= LOCAL
; // We start entry specific options
291 if (last_parent
!= root
)
292 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Missing }- ?\n");
296 mp_tmsg(MSGT_CFGPARSER
, MSGL_FATAL
,
297 "Error parsing option on the command line: %.*s\n",
300 play_tree_free(root
, 1);
304 extern int mp_msg_levels
[];
306 /* Parse some command line options early before main parsing.
307 * --noconfig prevents reading configuration files (otherwise done before
308 * command line parsing), and --really-quiet suppresses messages printed
309 * during normal options parsing.
311 int m_config_preparse_command_line(m_config_t
*config
, int argc
, char **argv
,
316 // Hack to shut up parser error messages
317 int msg_lvl_backup
= mp_msg_levels
[MSGT_CFGPARSER
];
318 mp_msg_levels
[MSGT_CFGPARSER
] = -11;
320 config
->mode
= M_COMMAND_LINE_PRE_PARSE
;
322 for (int i
= 1 ; i
< argc
; i
++) {
323 struct bstr opt
= bstr(argv
[i
]);
324 // No more options after --
325 if (!bstrcmp0(opt
, "--"))
327 struct bstr param
= bstr(i
+1 < argc
? argv
[i
+1] : NULL
);
329 if (!split_opt(&opt
, ¶m
, &old_syntax
))
330 continue; // Ignore non-option arguments
331 // Ignore invalid options
332 if (map_to_option(config
, old_syntax
, NULL
, &opt
, ¶m
) < 0)
334 // "-v" is handled here
335 if (!bstrcmp0(opt
, "v")) {
339 // Set, non-pre-parse options will be ignored
340 int r
= m_config_set_option(config
, opt
, param
, old_syntax
);
347 mp_msg_levels
[MSGT_CFGPARSER
] = msg_lvl_backup
;