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);
72 // Parse command line to set up config and playtree
73 play_tree_t
*m_config_parse_mp_command_line(m_config_t
*config
, int argc
,
77 bool no_more_opts
= false;
78 bool opt_exit
= false; // exit immediately after parsing (help options)
79 play_tree_t
*last_parent
, *last_entry
= NULL
, *root
;
82 assert(config
!= NULL
);
86 config
->mode
= M_COMMAND_LINE
;
88 #ifdef CONFIG_MACOSX_FINDER
89 root
= macosx_finder_args(config
, argc
, argv
);
94 last_parent
= root
= play_tree_new();
96 for (int i
= 1; i
< argc
; i
++) {
98 struct bstr opt
= bstr(argv
[i
]);
100 /* check for -- (no more options id.) except --help! */
101 if (!bstrcmp0(opt
, "--")) {
105 if (!bstrcmp0(opt
, "{")) {
106 play_tree_t
*entry
= play_tree_new();
108 if (last_parent
->flags
& PLAY_TREE_RND
)
109 entry
->flags
|= PLAY_TREE_RND
;
110 if (last_entry
== NULL
)
111 play_tree_set_child(last_parent
, entry
);
113 play_tree_append_entry(last_entry
, entry
);
120 if (!bstrcmp0(opt
, "}")) {
121 if (!last_parent
|| !last_parent
->parent
) {
122 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "too much }-\n");
125 last_entry
= last_parent
;
126 last_parent
= last_entry
->parent
;
130 struct bstr param
= bstr(i
+1 < argc
? argv
[i
+1] : NULL
);
132 if (!no_more_opts
&& split_opt(&opt
, ¶m
, &old_syntax
)) {
133 // Handle some special arguments outside option parser.
134 // --loop when it applies to a group of files (per-file is option)
135 if (bstrcasecmp0(opt
, "loop") == 0 &&
136 (!last_entry
|| last_entry
->child
)) {
138 int l
= bstrtoll(param
, &rest
, 0);
139 if (!param
.len
|| rest
.len
) {
140 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
141 "The loop option must be an integer: \"%.*s\"\n",
145 play_tree_t
*pt
= last_entry
? last_entry
: last_parent
;
150 } else if (bstrcasecmp0(opt
, "shuffle") == 0) {
151 if (last_entry
&& last_entry
->child
)
152 last_entry
->flags
|= PLAY_TREE_RND
;
154 last_parent
->flags
|= PLAY_TREE_RND
;
155 } else if (bstrcasecmp0(opt
, "noshuffle") == 0 ||
156 bstrcasecmp0(opt
, "no-shuffle") == 0) {
157 if (last_entry
&& last_entry
->child
)
158 last_entry
->flags
&= ~PLAY_TREE_RND
;
160 last_parent
->flags
&= ~PLAY_TREE_RND
;
161 } else if (bstrcasecmp0(opt
, "playlist") == 0) {
164 struct play_tree
*entry
= parse_playlist_file(config
, param
);
167 add_entry(&last_parent
, &last_entry
, entry
);
168 if ((last_parent
->flags
& PLAY_TREE_RND
) && entry
->child
)
169 entry
->flags
|= PLAY_TREE_RND
;
174 const struct m_option
*mp_opt
;
175 mp_opt
= m_config_get_option(config
, opt
);
177 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
178 "Unknown option on the command line: --%.*s\n",
183 if (mode
== GLOBAL
|| (mp_opt
->flags
& M_OPT_GLOBAL
)) {
184 r
= m_config_set_option(config
, opt
, param
, old_syntax
);
186 r
= m_config_check_option(config
, opt
, param
, old_syntax
);
188 play_tree_t
*pt
= last_entry
? last_entry
: last_parent
;
190 param
= bstr(NULL
); // for old_syntax case
191 play_tree_set_param(pt
, opt
, param
);
194 if (r
<= M_OPT_EXIT
) {
198 char *msg
= m_option_strerror(r
);
201 mp_tmsg(MSGT_CFGPARSER
, MSGL_FATAL
,
202 "Error parsing commandline option \"%.*s\": %s\n",
203 BSTR_P(orig_opt
), msg
);
209 } else { /* filename */
210 int is_dvdnav
= strstr(argv
[i
], "dvdnav://") != NULL
;
211 play_tree_t
*entry
= play_tree_new();
212 mp_msg(MSGT_CFGPARSER
, MSGL_DBG2
, "Adding file %s\n", argv
[i
]);
213 // expand DVD filename entries like dvd://1-3 into component titles
214 if (strstr(argv
[i
], "dvd://") != NULL
|| is_dvdnav
) {
215 int offset
= is_dvdnav
? 9 : 6;
216 char *splitpos
= strstr(argv
[i
] + offset
, "-");
217 if (splitpos
!= NULL
) {
218 int start_title
= strtol(argv
[i
] + offset
, NULL
, 10);
220 //entries like dvd://-2 imply start at title 1
221 if (start_title
< 0) {
222 end_title
= abs(start_title
);
225 end_title
= strtol(splitpos
+ 1, NULL
, 10);
227 if (dvd_range(start_title
) && dvd_range(end_title
)
228 && (start_title
< end_title
)) {
229 for (int j
= start_title
; j
<= end_title
; j
++) {
230 if (j
!= start_title
)
231 entry
= play_tree_new();
233 snprintf(entbuf
, sizeof(entbuf
),
234 is_dvdnav
? "dvdnav://%d" : "dvd://%d", j
);
235 play_tree_add_file(entry
, entbuf
);
236 add_entry(&last_parent
, &last_entry
, entry
);
240 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
,
241 "Invalid play entry %s\n", argv
[i
]);
243 } else // dvd:// or dvd://x entry
244 play_tree_add_file(entry
, argv
[i
]);
246 play_tree_add_file(entry
, argv
[i
]);
248 // Lock stdin if it will be used as input
249 if (strcasecmp(argv
[i
], "-") == 0)
250 m_config_set_option0(config
, "consolecontrols", "no", false);
251 add_entry(&last_parent
, &last_entry
, entry
);
252 mode
= LOCAL
; // We start entry specific options
258 if (last_parent
!= root
)
259 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "Missing }- ?\n");
263 mp_tmsg(MSGT_CFGPARSER
, MSGL_FATAL
,
264 "Error parsing option on the command line: %.*s\n",
267 play_tree_free(root
, 1);
271 extern int mp_msg_levels
[];
273 /* Parse some command line options early before main parsing.
274 * --noconfig prevents reading configuration files (otherwise done before
275 * command line parsing), and --really-quiet suppresses messages printed
276 * during normal options parsing.
278 int m_config_preparse_command_line(m_config_t
*config
, int argc
, char **argv
)
282 // Hack to shut up parser error messages
283 int msg_lvl_backup
= mp_msg_levels
[MSGT_CFGPARSER
];
284 mp_msg_levels
[MSGT_CFGPARSER
] = -11;
286 config
->mode
= M_COMMAND_LINE_PRE_PARSE
;
288 for (int i
= 1 ; i
< argc
; i
++) {
289 struct bstr opt
= bstr(argv
[i
]);
290 // No more options after --
291 if (!bstrcmp0(opt
, "--"))
293 struct bstr param
= bstr(i
+1 < argc
? argv
[i
+1] : NULL
);
295 if (!split_opt(&opt
, ¶m
, &old_syntax
))
296 continue; // Ignore non-option arguments
297 // Ignore invalid options
298 if (!m_config_get_option(config
, opt
))
300 // Set, non-pre-parse options will be ignored
301 int r
= m_config_set_option(config
, opt
, param
, old_syntax
);
308 mp_msg_levels
[MSGT_CFGPARSER
] = msg_lvl_backup
;