restore options alphabetical order
[mplayer.git] / parser-cfg.c
blobeec28f5bf1ad470b5406452b8bcbdcf255351886
2 /// \defgroup ConfigParsers Config parsers
3 ///
4 /// The \ref ConfigParsers make use of the \ref Config to setup the config variables,
5 /// the command line parsers also build the playlist.
6 ///@{
8 /// \file
10 #include "config.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <errno.h>
16 #include <ctype.h>
18 #ifdef MP_DEBUG
19 #include <assert.h>
20 #endif
22 #include "parser-cfg.h"
23 #include "mp_msg.h"
24 #include "m_option.h"
25 #include "m_config.h"
27 /// Maximal include depth.
28 #define MAX_RECURSION_DEPTH 8
30 /// Current include depth.
31 static int recursion_depth = 0;
33 /// Setup the \ref Config from a config file.
34 /** \param config The config object.
35 * \param conffile Path to the config file.
36 * \return 1 on sucess, -1 on error.
38 int m_config_parse_config_file(m_config_t* config, char *conffile)
40 #define PRINT_LINENUM mp_msg(MSGT_CFGPARSER,MSGL_V,"%s(%d): ", conffile, line_num)
41 #define MAX_LINE_LEN 10000
42 #define MAX_OPT_LEN 1000
43 #define MAX_PARAM_LEN 1500
44 FILE *fp;
45 char *line;
46 char opt[MAX_OPT_LEN + 1];
47 char param[MAX_PARAM_LEN + 1];
48 char c; /* for the "" and '' check */
49 int tmp;
50 int line_num = 0;
51 int line_pos; /* line pos */
52 int opt_pos; /* opt pos */
53 int param_pos; /* param pos */
54 int ret = 1;
55 int errors = 0;
56 int prev_mode = config->mode;
57 m_profile_t* profile = NULL;
59 #ifdef MP_DEBUG
60 assert(config != NULL);
61 // assert(conf_list != NULL);
62 #endif
63 mp_msg(MSGT_CFGPARSER,MSGL_V,"Reading config file %s", conffile);
65 if (recursion_depth > MAX_RECURSION_DEPTH) {
66 mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n");
67 ret = -1;
68 goto out;
69 } else
71 config->mode = M_CONFIG_FILE;
73 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
74 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno));
75 ret = -1;
76 goto out;
77 } else
79 mp_msg(MSGT_CFGPARSER,MSGL_V,"\n");
81 if ((fp = fopen(conffile, "r")) == NULL) {
82 mp_msg(MSGT_CFGPARSER,MSGL_V,": %s\n", strerror(errno));
83 free(line);
84 ret = 0;
85 goto out;
88 while (fgets(line, MAX_LINE_LEN, fp)) {
89 if (errors >= 16) {
90 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
91 goto out;
94 line_num++;
95 line_pos = 0;
97 /* skip whitespaces */
98 while (isspace(line[line_pos]))
99 ++line_pos;
101 /* EOL / comment */
102 if (line[line_pos] == '\0' || line[line_pos] == '#')
103 continue;
105 /* read option. */
106 for (opt_pos = 0; isprint(line[line_pos]) &&
107 line[line_pos] != ' ' &&
108 line[line_pos] != '#' &&
109 line[line_pos] != '='; /* NOTHING */) {
110 opt[opt_pos++] = line[line_pos++];
111 if (opt_pos >= MAX_OPT_LEN) {
112 PRINT_LINENUM;
113 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option at line %d\n",line_num);
114 errors++;
115 ret = -1;
116 goto nextline;
119 if (opt_pos == 0) {
120 PRINT_LINENUM;
121 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error at line %d\n",line_num);
122 ret = -1;
123 errors++;
124 continue;
126 opt[opt_pos] = '\0';
128 /* Profile declaration */
129 if(opt_pos > 2 && opt[0] == '[' && opt[opt_pos-1] == ']') {
130 opt[opt_pos-1] = '\0';
131 if(strcmp(opt+1,"default"))
132 profile = m_config_add_profile(config,opt+1);
133 else
134 profile = NULL;
135 continue;
138 #ifdef MP_DEBUG
139 PRINT_LINENUM;
140 mp_msg(MSGT_CFGPARSER,MSGL_V,"option: %s\n", opt);
141 #endif
143 /* skip whitespaces */
144 while (isspace(line[line_pos]))
145 ++line_pos;
147 /* check '=' */
148 if (line[line_pos++] != '=') {
149 PRINT_LINENUM;
150 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
151 ret = -1;
152 errors++;
153 continue;
156 /* whitespaces... */
157 while (isspace(line[line_pos]))
158 ++line_pos;
160 /* read the parameter */
161 if (line[line_pos] == '"' || line[line_pos] == '\'') {
162 c = line[line_pos];
163 ++line_pos;
164 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
165 param[param_pos++] = line[line_pos++];
166 if (param_pos >= MAX_PARAM_LEN) {
167 PRINT_LINENUM;
168 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s has a too long parameter at line %d\n",opt,line_num);
169 ret = -1;
170 errors++;
171 goto nextline;
174 line_pos++; /* skip the closing " or ' */
175 } else {
176 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
177 && line[line_pos] != '#'; /* NOTHING */) {
178 param[param_pos++] = line[line_pos++];
179 if (param_pos >= MAX_PARAM_LEN) {
180 PRINT_LINENUM;
181 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
182 ret = -1;
183 errors++;
184 goto nextline;
188 param[param_pos] = '\0';
190 /* did we read a parameter? */
191 if (param_pos == 0) {
192 PRINT_LINENUM;
193 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
194 ret = -1;
195 errors++;
196 continue;
199 #ifdef MP_DEBUG
200 PRINT_LINENUM;
201 mp_msg(MSGT_CFGPARSER,MSGL_V,"parameter: %s\n", param);
202 #endif
204 /* now, check if we have some more chars on the line */
205 /* whitespace... */
206 while (isspace(line[line_pos]))
207 ++line_pos;
209 /* EOL / comment */
210 if (line[line_pos] != '\0' && line[line_pos] != '#') {
211 PRINT_LINENUM;
212 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line %d: %s\n",line_num, line+line_pos);
213 ret = -1;
216 if(profile) {
217 if(!strcmp(opt,"profile-desc"))
218 m_profile_set_desc(profile,param), tmp = 1;
219 else
220 tmp = m_config_set_profile_option(config,profile,
221 opt,param);
222 } else
223 tmp = m_config_set_option(config, opt, param);
224 if (tmp < 0) {
225 PRINT_LINENUM;
226 if(tmp == M_OPT_UNKNOWN) {
227 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Warning unknown option %s at line %d\n", opt,line_num);
228 continue;
230 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Error parsing option %s=%s at line %d\n",opt,param,line_num);
231 ret = -1;
232 errors++;
233 continue;
234 /* break */
236 nextline:
240 free(line);
241 fclose(fp);
242 out:
243 config->mode = prev_mode;
244 --recursion_depth;
245 return ret;
248 extern int mp_msg_levels[];
250 /// Parse the command line option that must be handled at startup.
251 int m_config_preparse_command_line(m_config_t *config, int argc, char **argv)
253 int msg_lvl, i, r, ret = 0;
254 char* arg;
255 m_option_t* opt;
257 // Hack to shutup the parser error messages.
258 msg_lvl = mp_msg_levels[MSGT_CFGPARSER];
259 mp_msg_levels[MSGT_CFGPARSER] = -11;
261 config->mode = M_COMMAND_LINE_PRE_PARSE;
263 for(i = 1 ; i < argc ; i++) {
264 arg = argv[i];
265 // Ignore non option
266 if(arg[0] != '-' || arg[1] == 0) continue;
267 arg++;
268 // No more options after --
269 if(arg[0] == '-' && arg[1] == 0) break;
271 opt = m_config_get_option(config,arg);
272 // Ignore invalid option
273 if(!opt) continue;
274 // Set, non-pre-parse options will be ignored
275 r = m_config_set_option(config,arg,
276 i+1 < argc ? argv[i+1] : NULL);
277 if(r < 0) ret = r;
278 else i += r;
281 mp_msg_levels[MSGT_CFGPARSER] = msg_lvl;
283 return ret;
286 ///@}