Add Indexes to Options as suggested by Jaeho Shin.
[mplayer/glamo.git] / parser-cfg.c
blobc792ced3ac9c4815c85d59f6e4fca580941ca5f2
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 1000
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 = (char *) 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;
78 if ((fp = fopen(conffile, "r")) == NULL) {
79 mp_msg(MSGT_CFGPARSER,MSGL_V,": %s\n", strerror(errno));
80 free(line);
81 ret = 0;
82 goto out;
84 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"\n");
86 while (fgets(line, MAX_LINE_LEN, fp)) {
87 if (errors >= 16) {
88 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
89 goto out;
92 line_num++;
93 line_pos = 0;
95 /* skip whitespaces */
96 while (isspace(line[line_pos]))
97 ++line_pos;
99 /* EOL / comment */
100 if (line[line_pos] == '\0' || line[line_pos] == '#')
101 continue;
103 /* read option. */
104 for (opt_pos = 0; isprint(line[line_pos]) &&
105 line[line_pos] != ' ' &&
106 line[line_pos] != '#' &&
107 line[line_pos] != '='; /* NOTHING */) {
108 opt[opt_pos++] = line[line_pos++];
109 if (opt_pos >= MAX_OPT_LEN) {
110 PRINT_LINENUM;
111 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option at line %d\n",line_num);
112 errors++;
113 ret = -1;
114 goto nextline;
117 if (opt_pos == 0) {
118 PRINT_LINENUM;
119 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error at line %d\n",line_num);
120 ret = -1;
121 errors++;
122 continue;
124 opt[opt_pos] = '\0';
126 /* Profile declaration */
127 if(opt_pos > 2 && opt[0] == '[' && opt[opt_pos-1] == ']') {
128 opt[opt_pos-1] = '\0';
129 if(strcmp(opt+1,"default"))
130 profile = m_config_add_profile(config,opt+1);
131 else
132 profile = NULL;
133 continue;
136 #ifdef MP_DEBUG
137 PRINT_LINENUM;
138 mp_msg(MSGT_CFGPARSER,MSGL_V,"option: %s\n", opt);
139 #endif
141 /* skip whitespaces */
142 while (isspace(line[line_pos]))
143 ++line_pos;
145 /* check '=' */
146 if (line[line_pos++] != '=') {
147 PRINT_LINENUM;
148 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
149 ret = -1;
150 errors++;
151 continue;
154 /* whitespaces... */
155 while (isspace(line[line_pos]))
156 ++line_pos;
158 /* read the parameter */
159 if (line[line_pos] == '"' || line[line_pos] == '\'') {
160 c = line[line_pos];
161 ++line_pos;
162 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
163 param[param_pos++] = line[line_pos++];
164 if (param_pos >= MAX_PARAM_LEN) {
165 PRINT_LINENUM;
166 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s has a too long parameter at line %d\n",opt,line_num);
167 ret = -1;
168 errors++;
169 goto nextline;
172 line_pos++; /* skip the closing " or ' */
173 } else {
174 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
175 && line[line_pos] != '#'; /* NOTHING */) {
176 param[param_pos++] = line[line_pos++];
177 if (param_pos >= MAX_PARAM_LEN) {
178 PRINT_LINENUM;
179 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
180 ret = -1;
181 errors++;
182 goto nextline;
186 param[param_pos] = '\0';
188 /* did we read a parameter? */
189 if (param_pos == 0) {
190 PRINT_LINENUM;
191 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Option %s needs a parameter at line %d\n",opt,line_num);
192 ret = -1;
193 errors++;
194 continue;
197 #ifdef MP_DEBUG
198 PRINT_LINENUM;
199 mp_msg(MSGT_CFGPARSER,MSGL_V,"parameter: %s\n", param);
200 #endif
202 /* now, check if we have some more chars on the line */
203 /* whitespace... */
204 while (isspace(line[line_pos]))
205 ++line_pos;
207 /* EOL / comment */
208 if (line[line_pos] != '\0' && line[line_pos] != '#') {
209 PRINT_LINENUM;
210 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line %d: %s\n",line_num, line+line_pos);
211 ret = -1;
214 if(profile) {
215 if(!strcmp(opt,"profile-desc"))
216 m_profile_set_desc(profile,param), tmp = 1;
217 else
218 tmp = m_config_set_profile_option(config,profile,
219 opt,param);
220 } else
221 tmp = m_config_set_option(config, opt, param);
222 if (tmp < 0) {
223 PRINT_LINENUM;
224 if(tmp == M_OPT_UNKNOWN) {
225 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Warning unknown option %s at line %d\n", opt,line_num);
226 continue;
228 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Error parsing option %s=%s at line %d\n",opt,param,line_num);
229 ret = -1;
230 errors++;
231 continue;
232 /* break */
234 nextline:
238 free(line);
239 fclose(fp);
240 out:
241 config->mode = prev_mode;
242 --recursion_depth;
243 return ret;
246 ///@}