3 /// \ingroup ConfigParsers Playtree
21 #include "parser-mpcmd.h"
23 static int recursion_depth
= 0;
30 #define dvd_range(a) (a>0 && a<256)
31 #define UNSET_GLOBAL (mode = LOCAL)
32 // Use this 1 if you want to have only global option (no per file option)
33 // #define UNSET_GLOBAL (mode = GLOBAL)
36 static int is_entry_option(struct m_config
*mconfig
, char *opt
, char *param
,
39 play_tree_t
* entry
= NULL
;
43 if(strcasecmp(opt
,"playlist") == 0) { // We handle playlist here
45 return M_OPT_MISSING_PARAM
;
47 entry
= parse_playlist_file(mconfig
, param
);
58 static inline void add_entry(play_tree_t
**last_parentp
,
59 play_tree_t
**last_entryp
, play_tree_t
*entry
) {
60 if(*last_entryp
== NULL
)
61 play_tree_set_child(*last_parentp
,entry
);
63 play_tree_append_entry(*last_entryp
,entry
);
67 /// Setup the \ref Config from command line arguments and build a playtree.
68 /** \ingroup ConfigParsers
71 m_config_parse_mp_command_line(m_config_t
*config
, int argc
, char **argv
)
73 int i
,j
,start_title
=-1,end_title
=-1;
74 char *opt
,*splitpos
=NULL
;
77 int opt_exit
= 0; // flag indicating whether mplayer should exit without playing anything
78 play_tree_t
*last_parent
, *last_entry
= NULL
, *root
;
79 #ifdef CONFIG_MACOSX_FINDER
80 play_tree_t
*macosx_finder_args(m_config_t
*, int , char **);
84 assert(config
!= NULL
);
89 config
->mode
= M_COMMAND_LINE
;
91 #ifdef CONFIG_MACOSX_FINDER
92 root
=macosx_finder_args(config
, argc
, argv
);
97 last_parent
= root
= play_tree_new();
98 /* in order to work recursion detection properly in parse_config_file */
101 for (i
= 1; i
< argc
; i
++) {
104 /* check for -- (no more options id.) except --help! */
105 if ((*opt
== '-') && (*(opt
+1) == '-') && (*(opt
+2) == 0))
110 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
, "'--' indicates no more options, but no filename was given on the command line.\n");
115 if((opt
[0] == '{') && (opt
[1] == '\0'))
117 play_tree_t
* entry
= play_tree_new();
119 if(last_parent
->flags
& PLAY_TREE_RND
)
120 entry
->flags
|= PLAY_TREE_RND
;
121 if(last_entry
== NULL
) {
122 play_tree_set_child(last_parent
,entry
);
124 play_tree_append_entry(last_entry
,entry
);
131 if((opt
[0] == '}') && (opt
[1] == '\0'))
133 if( ! last_parent
|| ! last_parent
->parent
) {
134 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
, "too much }-\n");
137 last_entry
= last_parent
;
138 last_parent
= last_entry
->parent
;
142 if ((no_more_opts
== 0) && (*opt
== '-') && (*(opt
+1) != 0)) /* option */
145 /* remove trailing '-' */
148 mp_msg(MSGT_CFGPARSER
, MSGL_DBG3
, "this_opt = option: %s\n", opt
);
149 // We handle here some specific option
150 // Loop option when it apply to a group
151 if(strcasecmp(opt
,"loop") == 0 &&
152 (! last_entry
|| last_entry
->child
) ) {
155 l
= (i
+1<argc
) ? strtol(argv
[i
+1],&end
,0) : 0;
156 if(!end
|| *end
!= '\0') {
157 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
, "The loop option must be an integer: %s\n", argv
[i
+1]);
158 tmp
= ERR_OUT_OF_RANGE
;
160 play_tree_t
* pt
= last_entry
? last_entry
: last_parent
;
165 } else if(strcasecmp(opt
,"shuffle") == 0) {
166 if(last_entry
&& last_entry
->child
)
167 last_entry
->flags
|= PLAY_TREE_RND
;
169 last_parent
->flags
|= PLAY_TREE_RND
;
170 } else if(strcasecmp(opt
,"noshuffle") == 0) {
171 if(last_entry
&& last_entry
->child
)
172 last_entry
->flags
&= ~PLAY_TREE_RND
;
174 last_parent
->flags
&= ~PLAY_TREE_RND
;
176 const m_option_t
* mp_opt
= NULL
;
177 play_tree_t
* entry
= NULL
;
179 tmp
= is_entry_option(config
, opt
,(i
+1<argc
) ? argv
[i
+ 1] : NULL
,&entry
);
180 if(tmp
> 0) { // It's an entry
182 add_entry(&last_parent
,&last_entry
,entry
);
183 if((last_parent
->flags
& PLAY_TREE_RND
) && entry
->child
)
184 entry
->flags
|= PLAY_TREE_RND
;
186 } else if(mode
== LOCAL
) // Entry is empty we have to drop his params
188 } else if(tmp
== 0) { // 'normal' options
189 mp_opt
= m_config_get_option(config
,opt
);
190 if (mp_opt
!= NULL
) { // Option exist
191 if(mode
== GLOBAL
|| (mp_opt
->flags
& M_OPT_GLOBAL
))
192 tmp
= (i
+1<argc
) ? m_config_set_option(config
, opt
, argv
[i
+ 1])
193 : m_config_set_option(config
, opt
, NULL
);
195 tmp
= m_config_check_option(config
, opt
, (i
+1<argc
) ? argv
[i
+ 1] : NULL
);
196 if(tmp
>= 0 && mode
!= DROP_LOCAL
) {
197 play_tree_t
* pt
= last_entry
? last_entry
: last_parent
;
198 play_tree_set_param(pt
,opt
, argv
[i
+ 1]);
203 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
, "Unknown option on the command line: -%s\n", opt
);
208 if (tmp
<= M_OPT_EXIT
) {
210 tmp
= M_OPT_EXIT
- tmp
;
213 mp_tmsg(MSGT_CFGPARSER
, MSGL_FATAL
, "Error parsing option on the command line: -%s\n", opt
);
220 int is_dvdnav
= strstr(argv
[i
],"dvdnav://") != NULL
;
221 play_tree_t
* entry
= play_tree_new();
222 mp_msg(MSGT_CFGPARSER
, MSGL_DBG2
,"Adding file %s\n",argv
[i
]);
223 // if required expand DVD filename entries like dvd://1-3 into component titles
224 if ( strstr(argv
[i
],"dvd://") != NULL
|| is_dvdnav
)
226 int offset
= is_dvdnav
? 9 : 6;
227 splitpos
=strstr(argv
[i
]+offset
,"-");
230 start_title
=strtol(argv
[i
]+offset
,NULL
,10);
231 if (start_title
<0) { //entries like dvd://-2 start title implied 1
232 end_title
=abs(start_title
);
235 end_title
=strtol(splitpos
+1,NULL
,10);
238 if (dvd_range(start_title
) && dvd_range(end_title
) && (start_title
<end_title
))
240 for (j
=start_title
;j
<=end_title
;j
++)
243 entry
=play_tree_new();
244 snprintf(entbuf
,sizeof(entbuf
),is_dvdnav
? "dvdnav://%d" : "dvd://%d",j
);
245 play_tree_add_file(entry
,entbuf
);
246 add_entry(&last_parent
,&last_entry
,entry
);
250 mp_tmsg(MSGT_CFGPARSER
, MSGL_ERR
, "Invalid play entry %s\n", argv
[i
]);
253 } else { // dvd:// or dvd://x entry
254 play_tree_add_file(entry
,argv
[i
]);
257 play_tree_add_file(entry
,argv
[i
]);
260 // Lock stdin if it will be used as input
261 if(strcasecmp(argv
[i
],"-") == 0)
262 m_config_set_option(config
,"noconsolecontrols",NULL
);
263 add_entry(&last_parent
,&last_entry
,entry
);
264 UNSET_GLOBAL
; // We start entry specific options
272 if(last_parent
!= root
)
273 mp_msg(MSGT_CFGPARSER
, MSGL_ERR
,"Missing }- ?\n");
278 play_tree_free(root
,1);