Mercurial > mplayer.hg
annotate m_config.c @ 10730:67449e5936f3
fix 10l (computation based on uninitialized data which led to
incorrect field matching) and greatly improve selection logic. the
pullup core should be very accurate now, so try throwing tough samples
at it and report any failures! :)
author | rfelker |
---|---|
date | Sun, 31 Aug 2003 17:46:32 +0000 |
parents | 522afd56703c |
children | 11b249ef87b0 |
rev | line source |
---|---|
8164 | 1 #include "config.h" |
2 | |
3 #include <stdlib.h> | |
4 #include <stdio.h> | |
5 #include <errno.h> | |
6 #include <string.h> | |
7 #ifdef MP_DEBUG | |
8 #include <assert.h> | |
9 #endif | |
10 | |
11 #include "m_config.h" | |
12 #include "m_option.h" | |
13 #include "mp_msg.h" | |
14 | |
15 m_config_t* | |
16 m_config_new(void) { | |
17 m_config_t* config; | |
18 | |
19 config = (m_config_t*)calloc(1,sizeof(m_config_t)); | |
20 config->lvl = 1; // 0 Is the defaults | |
21 return config; | |
22 } | |
23 | |
24 void | |
25 m_config_free(m_config_t* config) { | |
26 m_config_option_t *i = config->opts, *ct; | |
27 m_config_save_slot_t *sl,*st; | |
28 | |
29 #ifdef MP_DEBUG | |
30 assert(config != NULL); | |
31 #endif | |
32 | |
33 while(i) { | |
34 sl = i->slots; | |
35 while(sl) { | |
36 m_option_free(i->opt,sl->data); | |
37 st = sl->prev; | |
38 free(sl); | |
39 sl = st; | |
40 } | |
41 if(i->name != i->opt->name) | |
42 free(i->name); | |
43 ct = i->next; | |
44 free(i); | |
45 ct = i; | |
46 } | |
47 free(config); | |
48 } | |
49 | |
50 void | |
51 m_config_push(m_config_t* config) { | |
52 m_config_option_t *co; | |
53 m_config_save_slot_t *slot; | |
54 | |
55 #ifdef MP_DEBUG | |
56 assert(config != NULL); | |
57 assert(config->lvl > 0); | |
58 #endif | |
59 | |
60 config->lvl++; | |
61 | |
62 for(co = config->opts ; co ; co = co->next ) { | |
63 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) | |
64 continue; | |
65 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE)) | |
66 continue; | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
67 if((co->opt->flags & M_OPT_OLD) && !(co->flags && M_CFG_OPT_SET)) |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
68 continue; |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
69 if(co->flags & M_CFG_OPT_ALIAS) |
8164 | 70 continue; |
71 | |
72 // Update the current status | |
73 m_option_save(co->opt,co->slots->data,co->opt->p); | |
74 | |
75 // Allocate a new slot | |
76 slot = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + co->opt->type->size); | |
77 slot->lvl = config->lvl; | |
78 slot->prev = co->slots; | |
79 co->slots = slot; | |
80 m_option_copy(co->opt,co->slots->data,co->slots->prev->data); | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
81 // Reset our set flag |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
82 co->flags &= ~M_CFG_OPT_SET; |
8164 | 83 } |
84 | |
85 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level is now %d\n",config->lvl); | |
86 } | |
87 | |
88 void | |
89 m_config_pop(m_config_t* config) { | |
90 m_config_option_t *co; | |
91 m_config_save_slot_t *slot; | |
92 | |
93 #ifdef MP_DEBUG | |
94 assert(config != NULL); | |
95 assert(config->lvl > 1); | |
96 #endif | |
97 | |
98 for(co = config->opts ; co ; co = co->next ) { | |
99 int pop = 0; | |
100 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) | |
101 continue; | |
102 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE)) | |
103 continue; | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
104 if(co->flags & M_CFG_OPT_ALIAS) |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
105 continue; |
8164 | 106 if(co->slots->lvl > config->lvl) |
107 mp_msg(MSGT_CFGPARSER, MSGL_WARN,"Too old save slot found from lvl %d : %d !!!\n",config->lvl,co->slots->lvl); | |
108 | |
109 while(co->slots->lvl >= config->lvl) { | |
110 m_option_free(co->opt,co->slots->data); | |
111 slot = co->slots; | |
112 co->slots = slot->prev; | |
113 free(slot); | |
114 pop++; | |
115 } | |
116 if(pop) // We removed some ctx -> set the previous value | |
117 m_option_set(co->opt,co->opt->p,co->slots->data); | |
118 } | |
119 | |
120 config->lvl--; | |
121 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->lvl); | |
122 } | |
123 | |
124 static void | |
125 m_config_add_option(m_config_t *config, m_option_t *arg, char* prefix) { | |
126 m_config_option_t *co; | |
127 m_config_save_slot_t* sl; | |
128 | |
129 #ifdef MP_DEBUG | |
130 assert(config != NULL); | |
131 assert(config->lvl > 0); | |
132 assert(arg != NULL); | |
133 #endif | |
134 | |
135 // Allocate a new entry for this option | |
136 co = (m_config_option_t*)calloc(1,sizeof(m_config_option_t) + arg->type->size); | |
137 co->opt = arg; | |
138 | |
139 // Fill in the full name | |
140 if(prefix && strlen(prefix) > 0) { | |
141 int l = strlen(prefix) + 1 + strlen(arg->name) + 1; | |
142 co->name = (char*) malloc(l); | |
143 sprintf(co->name,"%s:%s",prefix,arg->name); | |
144 } else | |
145 co->name = arg->name; | |
146 | |
147 // Option with childs -> add them | |
148 if(arg->type->flags & M_OPT_TYPE_HAS_CHILD) { | |
149 m_option_t *ol = arg->p; | |
150 int i; | |
151 for(i = 0 ; ol[i].name != NULL ; i++) | |
152 m_config_add_option(config,&ol[i], co->name); | |
153 } else { | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
154 m_config_option_t *i; |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
155 // Check if there is alredy an option pointing to this address |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
156 if(arg->p) { |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
157 for(i = config->opts ; i ; i = i->next ) { |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
158 if(i->opt->p == arg->p) { // So we don't save the same vars more than 1 time |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
159 co->slots = i->slots; |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
160 co->flags |= M_CFG_OPT_ALIAS; |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
161 break; |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
162 } |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
163 } |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
164 } |
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
165 if(!(co->flags & M_CFG_OPT_ALIAS)) { |
8164 | 166 // Allocate a slot for the defaults |
167 sl = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size); | |
168 m_option_save(arg,sl->data,(void**)arg->p); | |
169 // Hack to avoid too much trouble with dynamicly allocated data : | |
170 // We always use a dynamic version | |
171 if((arg->type->flags & M_OPT_TYPE_DYNAMIC) && arg->p && (*(void**)arg->p)) { | |
172 *(void**)arg->p = NULL; | |
173 m_option_set(arg,arg->p,sl->data); | |
174 } | |
175 sl->lvl = 0; | |
176 co->slots = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size); | |
177 co->slots->prev = sl; | |
178 co->slots->lvl = config->lvl; | |
179 m_option_copy(co->opt,co->slots->data,sl->data); | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
180 } // !M_OPT_ALIAS |
8164 | 181 } |
182 co->next = config->opts; | |
183 config->opts = co; | |
184 } | |
185 | |
186 int | |
187 m_config_register_options(m_config_t *config, m_option_t *args) { | |
188 int i; | |
189 | |
190 #ifdef MP_DEBUG | |
191 assert(config != NULL); | |
192 assert(config->lvl > 0); | |
193 assert(args != NULL); | |
194 #endif | |
195 | |
196 for(i = 0 ; args[i].name != NULL ; i++) | |
197 m_config_add_option(config,&args[i],NULL); | |
198 | |
199 return 1; | |
200 } | |
201 | |
202 static m_config_option_t* | |
203 m_config_get_co(m_config_t *config, char* arg) { | |
204 m_config_option_t *co; | |
205 | |
206 for(co = config->opts ; co ; co = co->next ) { | |
207 int l = strlen(co->name) - 1; | |
208 if((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) && | |
209 (co->name[l] == '*')) { | |
210 if(strncasecmp(co->name,arg,l) == 0) | |
211 return co; | |
212 } else if(strcasecmp(co->name,arg) == 0) | |
213 return co; | |
214 } | |
215 return NULL; | |
216 } | |
217 | |
218 static int | |
219 m_config_parse_option(m_config_t *config, char* arg, char* param,int set) { | |
220 m_config_option_t *co; | |
221 int r = 0; | |
222 | |
223 #ifdef MP_DEBUG | |
224 assert(config != NULL); | |
225 assert(config->lvl > 0); | |
226 assert(arg != NULL); | |
227 #endif | |
228 | |
229 co = m_config_get_co(config,arg); | |
8892 | 230 if(!co){ |
8894 | 231 // mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Unknown option: %s\n",arg); |
10595
522afd56703c
100l to albeu for his english grammar, and 10l to me becouse I noticed that lately (my backward compatibilty macro uses M_OPT_UNKNOWN)
alex
parents:
10594
diff
changeset
|
232 return M_OPT_UNKNOWN; |
8892 | 233 } |
8164 | 234 |
235 #ifdef MP_DEBUG | |
236 // This is the only mandatory function | |
237 assert(co->opt->type->parse); | |
238 #endif | |
239 | |
240 // Check if this option isn't forbiden in the current mode | |
241 if((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) { | |
8512 | 242 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"The %s option can't be used in a config file\n",arg); |
8164 | 243 return M_OPT_INVALID; |
244 } | |
245 if((config->mode == M_COMMAND_LINE) && (co->opt->flags & M_OPT_NOCMD)) { | |
8512 | 246 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"The %s option can't be used on the command line\n",arg); |
8164 | 247 return M_OPT_INVALID; |
248 } | |
249 | |
250 // Option with childs are a bit different to parse | |
251 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { | |
252 char** lst = NULL; | |
253 int i,sr; | |
254 // Parse the child options | |
9593
e9a2af584986
Add the new -vf option wich is the same as vop in reverse order.
albeu
parents:
9222
diff
changeset
|
255 r = m_option_parse(co->opt,arg,param,&lst,M_COMMAND_LINE); |
8164 | 256 // Set them now |
8894 | 257 if(r >= 0) |
8164 | 258 for(i = 0 ; lst && lst[2*i] ; i++) { |
259 int l = strlen(co->name) + 1 + strlen(lst[2*i]) + 1; | |
260 if(r >= 0) { | |
261 // Build the full name | |
262 char n[l]; | |
263 sprintf(n,"%s:%s",co->name,lst[2*i]); | |
264 sr = m_config_parse_option(config,n,lst[2*i+1],set); | |
8894 | 265 if(sr < 0){ |
10595
522afd56703c
100l to albeu for his english grammar, and 10l to me becouse I noticed that lately (my backward compatibilty macro uses M_OPT_UNKNOWN)
alex
parents:
10594
diff
changeset
|
266 if(sr == M_OPT_UNKNOWN){ |
8894 | 267 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Error: option '%s' has no suboption '%s'\n",co->name,lst[2*i]); |
268 r = M_OPT_INVALID; | |
269 } else | |
9222 | 270 if(sr == M_OPT_MISSING_PARAM){ |
271 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Error: suboption '%s' of '%s' must have a parameter!\n",lst[2*i],co->name); | |
272 r = M_OPT_INVALID; | |
273 } else | |
8894 | 274 r = sr; |
275 } | |
8164 | 276 } |
277 free(lst[2*i]); | |
278 free(lst[2*i+1]); | |
279 } | |
280 if(lst) free(lst); | |
281 } else | |
282 r = m_option_parse(co->opt,arg,param,set ? co->slots->data : NULL,config->mode); | |
283 | |
284 // Parsing failed ? | |
285 if(r < 0) | |
286 return r; | |
287 // Set the option | |
288 if(set) { | |
289 m_option_set(co->opt,co->opt->p,co->slots->data); | |
9912
39444d65c4cb
Don't save restore all options wich point to the same variable.
albeu
parents:
9593
diff
changeset
|
290 co->flags |= M_CFG_OPT_SET; |
8164 | 291 } |
292 | |
293 return r; | |
294 } | |
295 | |
296 int | |
297 m_config_set_option(m_config_t *config, char* arg, char* param) { | |
298 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Setting %s=%s\n",arg,param); | |
299 return m_config_parse_option(config,arg,param,1); | |
300 } | |
301 | |
302 int | |
303 m_config_check_option(m_config_t *config, char* arg, char* param) { | |
9222 | 304 int r; |
8164 | 305 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Checking %s=%s\n",arg,param); |
9222 | 306 r=m_config_parse_option(config,arg,param,0); |
307 if(r==M_OPT_MISSING_PARAM){ | |
308 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Error: option '%s' must have a parameter!\n",arg); | |
309 return M_OPT_INVALID; | |
310 } | |
311 return r; | |
8164 | 312 } |
313 | |
314 | |
315 m_option_t* | |
316 m_config_get_option(m_config_t *config, char* arg) { | |
317 m_config_option_t *co; | |
318 | |
319 #ifdef MP_DEBUG | |
320 assert(config != NULL); | |
321 assert(config->lvl > 0); | |
322 assert(arg != NULL); | |
323 #endif | |
324 | |
325 co = m_config_get_co(config,arg); | |
326 if(co) | |
327 return co->opt; | |
328 else | |
329 return NULL; | |
330 } | |
331 | |
332 void* | |
333 m_config_get_option_ptr(m_config_t *config, char* arg) { | |
334 m_option_t* conf; | |
335 | |
336 #ifdef MP_DEBUG | |
337 assert(config != NULL); | |
338 assert(arg != NULL); | |
339 #endif | |
340 | |
341 conf = m_config_get_option(config,arg); | |
342 if(!conf) return NULL; | |
343 return conf->p; | |
344 } | |
345 | |
346 void | |
347 m_config_print_option_list(m_config_t *config) { | |
348 char min[50],max[50]; | |
349 m_config_option_t* co; | |
350 int count = 0; | |
351 | |
352 if(!config->opts) return; | |
353 | |
354 printf("\n Name Type Min Max Global CL Cfg\n\n"); | |
355 for(co = config->opts ; co ; co = co->next) { | |
356 m_option_t* opt = co->opt; | |
357 if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue; | |
358 if(opt->flags & M_OPT_MIN) | |
359 sprintf(min,"%-8.0f",opt->min); | |
360 else | |
361 strcpy(min,"No"); | |
362 if(opt->flags & M_OPT_MAX) | |
363 sprintf(max,"%-8.0f",opt->max); | |
364 else | |
365 strcpy(max,"No"); | |
366 printf(" %-20.20s %-15.15s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n", | |
367 co->name, | |
368 co->opt->type->name, | |
369 min, | |
370 max, | |
371 opt->flags & CONF_GLOBAL ? "Yes" : "No", | |
372 opt->flags & CONF_NOCMD ? "No" : "Yes", | |
373 opt->flags & CONF_NOCFG ? "No" : "Yes"); | |
374 count++; | |
375 } | |
376 printf("\nTotal: %d options\n",count); | |
377 } |