Merge svn changes up to r30484
[mplayer/kovensky.git] / m_property.c
blob50b74b86eaf9c8966939e75b393abaf3834462fd
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 /// \file
20 /// \ingroup Properties
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <inttypes.h>
28 #include <unistd.h>
30 #include "m_option.h"
31 #include "m_property.h"
32 #include "mp_msg.h"
33 #include "help_mp.h"
35 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
37 static int do_action(const m_option_t* prop_list, const char* name,
38 int action, void* arg, void *ctx) {
39 const char* sep;
40 const m_option_t* prop;
41 m_property_action_t ka;
42 int r;
43 if((sep = strchr(name,'/')) && sep[1]) {
44 int len = sep-name;
45 char base[len+1];
46 memcpy(base,name,len);
47 base[len] = 0;
48 prop = m_option_list_find(prop_list, base);
49 ka.key = sep+1;
50 ka.action = action;
51 ka.arg = arg;
52 action = M_PROPERTY_KEY_ACTION;
53 arg = &ka;
54 } else
55 prop = m_option_list_find(prop_list, name);
56 if(!prop) return M_PROPERTY_UNKNOWN;
57 r = ((m_property_ctrl_f)prop->p)(prop,action,arg,ctx);
58 if(action == M_PROPERTY_GET_TYPE && r < 0) {
59 if(!arg) return M_PROPERTY_ERROR;
60 *(const m_option_t**)arg = prop;
61 return M_PROPERTY_OK;
63 return r;
66 int m_property_do(const m_option_t* prop_list, const char* name,
67 int action, void* arg, void *ctx) {
68 const m_option_t* opt;
69 void* val;
70 char* str;
71 int r;
73 switch(action) {
74 case M_PROPERTY_PRINT:
75 if((r = do_action(prop_list,name,M_PROPERTY_PRINT,arg,ctx)) >= 0)
76 return r;
77 // fallback on the default print for this type
78 case M_PROPERTY_TO_STRING:
79 if((r = do_action(prop_list,name,M_PROPERTY_TO_STRING,arg,ctx)) !=
80 M_PROPERTY_NOT_IMPLEMENTED)
81 return r;
82 // fallback on the options API. Get the type, value and print.
83 if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0)
84 return r;
85 val = calloc(1,opt->type->size);
86 if((r = do_action(prop_list,name,M_PROPERTY_GET,val,ctx)) <= 0) {
87 free(val);
88 return r;
90 if(!arg) return M_PROPERTY_ERROR;
91 str = m_option_print(opt,val);
92 free(val);
93 *(char**)arg = str == (char*)-1 ? NULL : str;
94 return str != (char*)-1;
95 case M_PROPERTY_PARSE:
96 // try the property own parsing func
97 if((r = do_action(prop_list,name,M_PROPERTY_PARSE,arg,ctx)) !=
98 M_PROPERTY_NOT_IMPLEMENTED)
99 return r;
100 // fallback on the options API, get the type and parse.
101 if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0)
102 return r;
103 if(!arg) return M_PROPERTY_ERROR;
104 val = calloc(1,opt->type->size);
105 if((r = m_option_parse(opt,opt->name,arg,val,M_CONFIG_FILE)) <= 0) {
106 free(val);
107 return r;
109 r = do_action(prop_list,name,M_PROPERTY_SET,val,ctx);
110 m_option_free(opt,val);
111 free(val);
112 return r;
114 return do_action(prop_list,name,action,arg,ctx);
117 char* m_properties_expand_string(const m_option_t* prop_list,char* str, void *ctx) {
118 int l,fr=0,pos=0,size=strlen(str)+512;
119 char *p = NULL,*e,*ret = malloc(size), num_val;
120 int skip = 0, lvl = 0, skip_lvl = 0;
122 while(str[0]) {
123 if(str[0] == '\\') {
124 int sl = 1;
125 switch(str[1]) {
126 case 'e':
127 p = "\x1b", l = 1; break;
128 case 'n':
129 p = "\n", l = 1; break;
130 case 'r':
131 p = "\r", l = 1; break;
132 case 't':
133 p = "\t", l = 1; break;
134 case 'x':
135 if(str[2]) {
136 char num[3] = { str[2], str[3], 0 };
137 char* end = num;
138 num_val = strtol(num,&end,16);
139 sl = end-num;
140 l = 1;
141 p = &num_val;
142 } else
143 l = 0;
144 break;
145 default:
146 p = str+1, l = 1;
148 str+=1+sl;
149 } else if(lvl > 0 && str[0] == ')') {
150 if(skip && lvl <= skip_lvl) skip = 0;
151 lvl--, str++, l = 0;
152 } else if(str[0] == '$' && str[1] == '{' && (e = strchr(str+2,'}'))) {
153 int pl = e-str-2;
154 char pname[pl+1];
155 memcpy(pname,str+2,pl);
156 pname[pl] = 0;
157 if(m_property_do(prop_list, pname,
158 M_PROPERTY_PRINT, &p, ctx) >= 0 && p)
159 l = strlen(p), fr = 1;
160 else
161 l = 0;
162 str = e+1;
163 } else if(str[0] == '?' && str[1] == '(' && (e = strchr(str+2,':'))) {
164 lvl++;
165 if(!skip) {
166 int is_not = str[2] == '!';
167 int pl = e - str - (is_not ? 3 : 2);
168 char pname[pl+1];
169 memcpy(pname, str + (is_not ? 3 : 2), pl);
170 pname[pl] = 0;
171 if(m_property_do(prop_list,pname,M_PROPERTY_GET,NULL,ctx) < 0) {
172 if (!is_not)
173 skip = 1, skip_lvl = lvl;
175 else if (is_not)
176 skip = 1, skip_lvl = lvl;
178 str = e+1, l = 0;
179 } else
180 p = str, l = 1, str++;
182 if(skip || l <= 0) continue;
184 if(pos+l+1 > size) {
185 size = pos+l+512;
186 ret = realloc(ret,size);
188 memcpy(ret+pos,p,l);
189 pos += l;
190 if(fr) free(p), fr = 0;
193 ret[pos] = 0;
194 return ret;
197 void m_properties_print_help_list(const m_option_t* list) {
198 char min[50],max[50];
199 int i,count = 0;
201 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\n Name Type Min Max\n\n");
202 for(i = 0 ; list[i].name ; i++) {
203 const m_option_t* opt = &list[i];
204 if(opt->flags & M_OPT_MIN)
205 sprintf(min,"%-8.0f",opt->min);
206 else
207 strcpy(min,"No");
208 if(opt->flags & M_OPT_MAX)
209 sprintf(max,"%-8.0f",opt->max);
210 else
211 strcpy(max,"No");
212 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s\n",
213 opt->name,
214 opt->type->name,
215 min,
216 max);
217 count++;
219 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count);
222 // Some generic property implementations
224 int m_property_int_ro(const m_option_t* prop,int action,
225 void* arg,int var) {
226 switch(action) {
227 case M_PROPERTY_GET:
228 if(!arg) return 0;
229 *(int*)arg = var;
230 return 1;
232 return M_PROPERTY_NOT_IMPLEMENTED;
235 int m_property_int_range(const m_option_t* prop,int action,
236 void* arg,int* var) {
237 switch(action) {
238 case M_PROPERTY_SET:
239 if(!arg) return 0;
240 M_PROPERTY_CLAMP(prop,*(int*)arg);
241 *var = *(int*)arg;
242 return 1;
243 case M_PROPERTY_STEP_UP:
244 case M_PROPERTY_STEP_DOWN:
245 *var += (arg ? *(int*)arg : 1) *
246 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
247 M_PROPERTY_CLAMP(prop,*var);
248 return 1;
250 return m_property_int_ro(prop,action,arg,*var);
253 int m_property_choice(const m_option_t* prop,int action,
254 void* arg,int* var) {
255 switch(action) {
256 case M_PROPERTY_STEP_UP:
257 case M_PROPERTY_STEP_DOWN:
258 *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max;
259 *var %= (int)prop->max+1;
260 return 1;
262 return m_property_int_range(prop,action,arg,var);
265 int m_property_flag_ro(const m_option_t* prop,int action,
266 void* arg,int var) {
267 switch(action) {
268 case M_PROPERTY_PRINT:
269 if(!arg) return 0;
270 *(char**)arg = strdup((var > prop->min) ?
271 mp_gtext("enabled") : mp_gtext("disabled"));
272 return 1;
274 return m_property_int_ro(prop,action,arg,var);
277 int m_property_flag(const m_option_t* prop,int action,
278 void* arg,int* var) {
279 switch(action) {
280 case M_PROPERTY_STEP_UP:
281 case M_PROPERTY_STEP_DOWN:
282 *var = *var == prop->min ? prop->max : prop->min;
283 return 1;
284 case M_PROPERTY_PRINT:
285 return m_property_flag_ro(prop, action, arg, *var);
287 return m_property_int_range(prop,action,arg,var);
290 int m_property_float_ro(const m_option_t* prop,int action,
291 void* arg,float var) {
292 switch(action) {
293 case M_PROPERTY_GET:
294 if(!arg) return 0;
295 *(float*)arg = var;
296 return 1;
297 case M_PROPERTY_PRINT:
298 if(!arg) return 0;
299 *(char**)arg = malloc(20);
300 sprintf(*(char**)arg,"%.2f",var);
301 return 1;
303 return M_PROPERTY_NOT_IMPLEMENTED;
306 int m_property_float_range(const m_option_t* prop,int action,
307 void* arg,float* var) {
308 switch(action) {
309 case M_PROPERTY_SET:
310 if(!arg) return 0;
311 M_PROPERTY_CLAMP(prop,*(float*)arg);
312 *var = *(float*)arg;
313 return 1;
314 case M_PROPERTY_STEP_UP:
315 case M_PROPERTY_STEP_DOWN:
316 *var += (arg ? *(float*)arg : 0.1) *
317 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
318 M_PROPERTY_CLAMP(prop,*var);
319 return 1;
321 return m_property_float_ro(prop,action,arg,*var);
324 int m_property_delay(const m_option_t* prop,int action,
325 void* arg,float* var) {
326 switch(action) {
327 case M_PROPERTY_PRINT:
328 if(!arg) return 0;
329 *(char**)arg = malloc(20);
330 sprintf(*(char**)arg,"%d ms",ROUND((*var)*1000));
331 return 1;
332 default:
333 return m_property_float_range(prop,action,arg,var);
337 int m_property_double_ro(const m_option_t* prop,int action,
338 void* arg,double var) {
339 switch(action) {
340 case M_PROPERTY_GET:
341 if(!arg) return 0;
342 *(double*)arg = var;
343 return 1;
344 case M_PROPERTY_PRINT:
345 if(!arg) return 0;
346 *(char**)arg = malloc(20);
347 sprintf(*(char**)arg,"%.2f",var);
348 return 1;
350 return M_PROPERTY_NOT_IMPLEMENTED;
353 int m_property_time_ro(const m_option_t* prop,int action,
354 void* arg,double var) {
355 switch(action) {
356 case M_PROPERTY_PRINT:
357 if (!arg)
358 return M_PROPERTY_ERROR;
359 else {
360 int h, m, s = var;
361 h = s / 3600;
362 s -= h * 3600;
363 m = s / 60;
364 s -= m * 60;
365 *(char **) arg = malloc(20);
366 if (h > 0)
367 sprintf(*(char **) arg, "%d:%02d:%02d", h, m, s);
368 else if (m > 0)
369 sprintf(*(char **) arg, "%d:%02d", m, s);
370 else
371 sprintf(*(char **) arg, "%d", s);
372 return M_PROPERTY_OK;
375 return m_property_double_ro(prop,action,arg,var);
378 int m_property_string_ro(const m_option_t* prop,int action,void* arg,char* str) {
379 switch(action) {
380 case M_PROPERTY_GET:
381 if(!arg) return 0;
382 *(char**)arg = str;
383 return 1;
384 case M_PROPERTY_PRINT:
385 if(!arg) return 0;
386 *(char**)arg = str ? strdup(str) : NULL;
387 return 1;
389 return M_PROPERTY_NOT_IMPLEMENTED;
392 int m_property_bitrate(const m_option_t* prop,int action,void* arg,int rate) {
393 switch(action) {
394 case M_PROPERTY_PRINT:
395 if (!arg)
396 return M_PROPERTY_ERROR;
397 *(char**)arg = malloc (16);
398 sprintf(*(char**)arg, "%d kbps", rate*8/1000);
399 return M_PROPERTY_OK;
401 return m_property_int_ro(prop, action, arg, rate);