DOCS/xml/README: improve
[mplayer/glamo.git] / parser-cfg.c
blob562200c56adb1d18bc9029914742c5e9ca1837fc
1 /*
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.
19 /// \defgroup ConfigParsers Config parsers
20 ///
21 /// The \ref ConfigParsers make use of the \ref Config to setup the config variables,
22 /// the command line parsers also build the playlist.
23 ///@{
25 /// \file
27 #include "config.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <ctype.h>
35 #ifdef MP_DEBUG
36 #include <assert.h>
37 #endif
39 #include "parser-cfg.h"
40 #include "mp_msg.h"
41 #include "m_option.h"
42 #include "m_config.h"
44 /// Maximal include depth.
45 #define MAX_RECURSION_DEPTH 8
47 /// Current include depth.
48 static int recursion_depth = 0;
50 /// Setup the \ref Config from a config file.
51 /** \param config The config object.
52 * \param conffile Path to the config file.
53 * \return 1 on sucess, -1 on error.
55 int m_config_parse_config_file(m_config_t* config, const char *conffile)
57 #define PRINT_LINENUM mp_msg(MSGT_CFGPARSER,MSGL_V,"%s(%d): ", conffile, line_num)
58 #define MAX_LINE_LEN 10000
59 #define MAX_OPT_LEN 1000
60 #define MAX_PARAM_LEN 1500
61 FILE *fp;
62 char *line;
63 char opt[MAX_OPT_LEN + 1];
64 char param[MAX_PARAM_LEN + 1];
65 char c; /* for the "" and '' check */
66 int tmp;
67 int line_num = 0;
68 int line_pos; /* line pos */
69 int opt_pos; /* opt pos */
70 int param_pos; /* param pos */
71 int ret = 1;
72 int errors = 0;
73 int prev_mode = config->mode;
74 m_profile_t* profile = NULL;
76 #ifdef MP_DEBUG
77 assert(config != NULL);
78 // assert(conf_list != NULL);
79 #endif
80 mp_msg(MSGT_CFGPARSER,MSGL_V,"Reading config file %s", conffile);
82 if (recursion_depth > MAX_RECURSION_DEPTH) {
83 mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n");
84 ret = -1;
85 goto out;
86 } else
88 config->mode = M_CONFIG_FILE;
90 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
91 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno));
92 ret = -1;
93 goto out;
94 } else
96 mp_msg(MSGT_CFGPARSER,MSGL_V,"\n");
98 if ((fp = fopen(conffile, "r")) == NULL) {
99 mp_msg(MSGT_CFGPARSER,MSGL_V,": %s\n", strerror(errno));
100 free(line);
101 ret = 0;
102 goto out;
105 while (fgets(line, MAX_LINE_LEN, fp)) {
106 if (errors >= 16) {
107 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
108 goto out;
111 line_num++;
112 line_pos = 0;
114 /* skip whitespaces */
115 while (isspace(line[line_pos]))
116 ++line_pos;
118 /* EOL / comment */
119 if (line[line_pos] == '\0' || line[line_pos] == '#')
120 continue;
122 /* read option. */
123 for (opt_pos = 0; isprint(line[line_pos]) &&
124 line[line_pos] != ' ' &&
125 line[line_pos] != '#' &&
126 line[line_pos] != '='; /* NOTHING */) {
127 opt[opt_pos++] = line[line_pos++];
128 if (opt_pos >= MAX_OPT_LEN) {
129 PRINT_LINENUM;
130 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option at line %d\n",line_num);
131 errors++;
132 ret = -1;
133 goto nextline;
136 if (opt_pos == 0) {
137 PRINT_LINENUM;
138 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error at line %d\n",line_num);
139 ret = -1;
140 errors++;
141 continue;
143 opt[opt_pos] = '\0';
145 /* Profile declaration */
146 if(opt_pos > 2 && opt[0] == '[' && opt[opt_pos-1] == ']') {
147 opt[opt_pos-1] = '\0';
148 if(strcmp(opt+1,"default"))
149 profile = m_config_add_profile(config,opt+1);
150 else
151 profile = NULL;
152 continue;
155 #ifdef MP_DEBUG
156 PRINT_LINENUM;
157 mp_msg(MSGT_CFGPARSER,MSGL_V,"option: %s\n", opt);
158 #endif
160 /* skip whitespaces */
161 while (isspace(line[line_pos]))
162 ++line_pos;
164 /* check '=' */
165 if (line[line_pos++] != '=') {
166 PRINT_LINENUM;
167 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
168 ret = -1;
169 errors++;
170 continue;
173 /* whitespaces... */
174 while (isspace(line[line_pos]))
175 ++line_pos;
177 /* read the parameter */
178 if (line[line_pos] == '"' || line[line_pos] == '\'') {
179 c = line[line_pos];
180 ++line_pos;
181 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
182 param[param_pos++] = line[line_pos++];
183 if (param_pos >= MAX_PARAM_LEN) {
184 PRINT_LINENUM;
185 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s has a too long parameter at line %d\n",opt,line_num);
186 ret = -1;
187 errors++;
188 goto nextline;
191 line_pos++; /* skip the closing " or ' */
192 } else {
193 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
194 && line[line_pos] != '#'; /* NOTHING */) {
195 param[param_pos++] = line[line_pos++];
196 if (param_pos >= MAX_PARAM_LEN) {
197 PRINT_LINENUM;
198 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
199 ret = -1;
200 errors++;
201 goto nextline;
205 param[param_pos] = '\0';
207 /* did we read a parameter? */
208 if (param_pos == 0) {
209 PRINT_LINENUM;
210 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
211 ret = -1;
212 errors++;
213 continue;
216 #ifdef MP_DEBUG
217 PRINT_LINENUM;
218 mp_msg(MSGT_CFGPARSER,MSGL_V,"parameter: %s\n", param);
219 #endif
221 /* now, check if we have some more chars on the line */
222 /* whitespace... */
223 while (isspace(line[line_pos]))
224 ++line_pos;
226 /* EOL / comment */
227 if (line[line_pos] != '\0' && line[line_pos] != '#') {
228 PRINT_LINENUM;
229 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line %d: %s\n",line_num, line+line_pos);
230 ret = -1;
233 if(profile) {
234 if(!strcmp(opt,"profile-desc"))
235 m_profile_set_desc(profile,param), tmp = 1;
236 else
237 tmp = m_config_set_profile_option(config,profile,
238 opt,param);
239 } else
240 tmp = m_config_set_option(config, opt, param);
241 if (tmp < 0) {
242 PRINT_LINENUM;
243 if(tmp == M_OPT_UNKNOWN) {
244 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Warning unknown option %s at line %d\n", opt,line_num);
245 continue;
247 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Error parsing option %s=%s at line %d\n",opt,param,line_num);
248 ret = -1;
249 errors++;
250 continue;
251 /* break */
253 nextline:
257 free(line);
258 fclose(fp);
259 out:
260 config->mode = prev_mode;
261 --recursion_depth;
262 return ret;
265 extern int mp_msg_levels[];
267 /// Parse the command line option that must be handled at startup.
268 int m_config_preparse_command_line(m_config_t *config, int argc, char **argv)
270 int msg_lvl, i, r, ret = 0;
271 char* arg;
273 // Hack to shutup the parser error messages.
274 msg_lvl = mp_msg_levels[MSGT_CFGPARSER];
275 mp_msg_levels[MSGT_CFGPARSER] = -11;
277 config->mode = M_COMMAND_LINE_PRE_PARSE;
279 for(i = 1 ; i < argc ; i++) {
280 const m_option_t* opt;
281 arg = argv[i];
282 // Ignore non option
283 if(arg[0] != '-' || arg[1] == 0) continue;
284 arg++;
285 // No more options after --
286 if(arg[0] == '-' && arg[1] == 0) break;
288 opt = m_config_get_option(config,arg);
289 // Ignore invalid option
290 if(!opt) continue;
291 // Set, non-pre-parse options will be ignored
292 r = m_config_set_option(config,arg,
293 i+1 < argc ? argv[i+1] : NULL);
294 if(r < 0) ret = r;
295 else i += r;
298 mp_msg_levels[MSGT_CFGPARSER] = msg_lvl;
300 return ret;
303 ///@}