Add a comment that explains why this header has no multiple inclusion guards.
[mplayer/greg.git] / parser-cfg.c
blob7976939106c5c7e3f9854481da8f1ccdd7495ba0
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 "mp_msg.h"
23 #include "m_option.h"
24 #include "m_config.h"
26 /// Maximal include depth.
27 #define MAX_RECURSION_DEPTH 8
29 /// Current include depth.
30 static int recursion_depth = 0;
32 /// Setup the \ref Config from a config file.
33 /** \param config The config object.
34 * \param conffile Path to the config file.
35 * \return 1 on sucess, -1 on error.
37 int m_config_parse_config_file(m_config_t* config, char *conffile)
39 #define PRINT_LINENUM mp_msg(MSGT_CFGPARSER,MSGL_V,"%s(%d): ", conffile, line_num)
40 #define MAX_LINE_LEN 10000
41 #define MAX_OPT_LEN 1000
42 #define MAX_PARAM_LEN 1500
43 FILE *fp;
44 char *line;
45 char opt[MAX_OPT_LEN + 1];
46 char param[MAX_PARAM_LEN + 1];
47 char c; /* for the "" and '' check */
48 int tmp;
49 int line_num = 0;
50 int line_pos; /* line pos */
51 int opt_pos; /* opt pos */
52 int param_pos; /* param pos */
53 int ret = 1;
54 int errors = 0;
55 int prev_mode = config->mode;
56 m_profile_t* profile = NULL;
58 #ifdef MP_DEBUG
59 assert(config != NULL);
60 // assert(conf_list != NULL);
61 #endif
62 mp_msg(MSGT_CFGPARSER,MSGL_V,"Reading config file %s", conffile);
64 if (recursion_depth > MAX_RECURSION_DEPTH) {
65 mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n");
66 ret = -1;
67 goto out;
68 } else
70 config->mode = M_CONFIG_FILE;
72 if ((line = malloc(MAX_LINE_LEN + 1)) == NULL) {
73 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno));
74 ret = -1;
75 goto out;
76 } else
78 mp_msg(MSGT_CFGPARSER,MSGL_V,"\n");
80 if ((fp = fopen(conffile, "r")) == NULL) {
81 mp_msg(MSGT_CFGPARSER,MSGL_V,": %s\n", strerror(errno));
82 free(line);
83 ret = 0;
84 goto out;
87 while (fgets(line, MAX_LINE_LEN, fp)) {
88 if (errors >= 16) {
89 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
90 goto out;
93 line_num++;
94 line_pos = 0;
96 /* skip whitespaces */
97 while (isspace(line[line_pos]))
98 ++line_pos;
100 /* EOL / comment */
101 if (line[line_pos] == '\0' || line[line_pos] == '#')
102 continue;
104 /* read option. */
105 for (opt_pos = 0; isprint(line[line_pos]) &&
106 line[line_pos] != ' ' &&
107 line[line_pos] != '#' &&
108 line[line_pos] != '='; /* NOTHING */) {
109 opt[opt_pos++] = line[line_pos++];
110 if (opt_pos >= MAX_OPT_LEN) {
111 PRINT_LINENUM;
112 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option at line %d\n",line_num);
113 errors++;
114 ret = -1;
115 goto nextline;
118 if (opt_pos == 0) {
119 PRINT_LINENUM;
120 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error at line %d\n",line_num);
121 ret = -1;
122 errors++;
123 continue;
125 opt[opt_pos] = '\0';
127 /* Profile declaration */
128 if(opt_pos > 2 && opt[0] == '[' && opt[opt_pos-1] == ']') {
129 opt[opt_pos-1] = '\0';
130 if(strcmp(opt+1,"default"))
131 profile = m_config_add_profile(config,opt+1);
132 else
133 profile = NULL;
134 continue;
137 #ifdef MP_DEBUG
138 PRINT_LINENUM;
139 mp_msg(MSGT_CFGPARSER,MSGL_V,"option: %s\n", opt);
140 #endif
142 /* skip whitespaces */
143 while (isspace(line[line_pos]))
144 ++line_pos;
146 /* check '=' */
147 if (line[line_pos++] != '=') {
148 PRINT_LINENUM;
149 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
150 ret = -1;
151 errors++;
152 continue;
155 /* whitespaces... */
156 while (isspace(line[line_pos]))
157 ++line_pos;
159 /* read the parameter */
160 if (line[line_pos] == '"' || line[line_pos] == '\'') {
161 c = line[line_pos];
162 ++line_pos;
163 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
164 param[param_pos++] = line[line_pos++];
165 if (param_pos >= MAX_PARAM_LEN) {
166 PRINT_LINENUM;
167 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s has a too long parameter at line %d\n",opt,line_num);
168 ret = -1;
169 errors++;
170 goto nextline;
173 line_pos++; /* skip the closing " or ' */
174 } else {
175 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
176 && line[line_pos] != '#'; /* NOTHING */) {
177 param[param_pos++] = line[line_pos++];
178 if (param_pos >= MAX_PARAM_LEN) {
179 PRINT_LINENUM;
180 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
181 ret = -1;
182 errors++;
183 goto nextline;
187 param[param_pos] = '\0';
189 /* did we read a parameter? */
190 if (param_pos == 0) {
191 PRINT_LINENUM;
192 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
193 ret = -1;
194 errors++;
195 continue;
198 #ifdef MP_DEBUG
199 PRINT_LINENUM;
200 mp_msg(MSGT_CFGPARSER,MSGL_V,"parameter: %s\n", param);
201 #endif
203 /* now, check if we have some more chars on the line */
204 /* whitespace... */
205 while (isspace(line[line_pos]))
206 ++line_pos;
208 /* EOL / comment */
209 if (line[line_pos] != '\0' && line[line_pos] != '#') {
210 PRINT_LINENUM;
211 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line %d: %s\n",line_num, line+line_pos);
212 ret = -1;
215 if(profile) {
216 if(!strcmp(opt,"profile-desc"))
217 m_profile_set_desc(profile,param), tmp = 1;
218 else
219 tmp = m_config_set_profile_option(config,profile,
220 opt,param);
221 } else
222 tmp = m_config_set_option(config, opt, param);
223 if (tmp < 0) {
224 PRINT_LINENUM;
225 if(tmp == M_OPT_UNKNOWN) {
226 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Warning unknown option %s at line %d\n", opt,line_num);
227 continue;
229 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Error parsing option %s=%s at line %d\n",opt,param,line_num);
230 ret = -1;
231 errors++;
232 continue;
233 /* break */
235 nextline:
239 free(line);
240 fclose(fp);
241 out:
242 config->mode = prev_mode;
243 --recursion_depth;
244 return ret;
247 ///@}