10l, avoid crash on invalid subtitle id
[mplayer/glamo.git] / m_property.c
blobfe28f145b547ab8707abd4b27acea8de7a21203b
2 /// \file
3 /// \ingroup Properties
5 #include "config.h"
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <unistd.h>
13 #include "m_option.h"
14 #include "m_property.h"
15 #include "mp_msg.h"
16 #include "help_mp.h"
18 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
20 int m_property_do(m_option_t* prop, int action, void* arg, void *ctx) {
21 if(!prop) return M_PROPERTY_UNKNOWN;
22 return ((m_property_ctrl_f)prop->p)(prop,action,arg,ctx);
26 char* m_property_print(m_option_t* prop, void *ctx) {
27 m_property_ctrl_f ctrl;
28 void* val;
29 char* ret;
31 if(!prop) return NULL;
33 ctrl = prop->p;
34 // look if the property have it's own print func
35 if(ctrl(prop,M_PROPERTY_PRINT,&ret, ctx) >= 0)
36 return ret;
37 // fallback on the default print for this type
38 val = calloc(1,prop->type->size);
39 if(ctrl(prop,M_PROPERTY_GET,val,ctx) <= 0) {
40 free(val);
41 return NULL;
43 ret = m_option_print(prop,val);
44 free(val);
45 return ret == (char*)-1 ? NULL : ret;
48 int m_property_parse(m_option_t* prop, char* txt, void *ctx) {
49 m_property_ctrl_f ctrl;
50 void* val;
51 int r;
53 if(!prop) return M_PROPERTY_UNKNOWN;
55 ctrl = prop->p;
56 // try the property own parsing func
57 if((r = ctrl(prop,M_PROPERTY_PARSE,txt,ctx)) != M_PROPERTY_NOT_IMPLEMENTED)
58 return r;
59 // fallback on the default
60 val = calloc(1,prop->type->size);
61 if((r = m_option_parse(prop,prop->name,txt,val,M_CONFIG_FILE)) <= 0) {
62 free(val);
63 return r;
65 r = ctrl(prop,M_PROPERTY_SET,val,ctx);
66 m_option_free(prop,val);
67 free(val);
68 return r;
71 char* m_properties_expand_string(m_option_t* prop_list,char* str, void *ctx) {
72 int l,fr=0,pos=0,size=strlen(str)+512;
73 char *p = NULL,*e,*ret = malloc(size), num_val;
74 int skip = 0, lvl = 0, skip_lvl = 0;
76 while(str[0]) {
77 if(str[0] == '\\') {
78 int sl = 1;
79 switch(str[1]) {
80 case 'e':
81 p = "\x1b", l = 1; break;
82 case 'n':
83 p = "\n", l = 1; break;
84 case 'r':
85 p = "\r", l = 1; break;
86 case 't':
87 p = "\t", l = 1; break;
88 case 'x':
89 if(str[2]) {
90 char num[3] = { str[2], str[3], 0 };
91 char* end = num;
92 num_val = strtol(num,&end,16);
93 sl = end-num;
94 l = 1;
95 p = &num_val;
96 } else
97 l = 0;
98 break;
99 default:
100 p = str+1, l = 1;
102 str+=1+sl;
103 } else if(lvl > 0 && str[0] == ')') {
104 if(skip && lvl <= skip_lvl) skip = 0;
105 lvl--, str++, l = 0;
106 } else if(str[0] == '$' && str[1] == '{' && (e = strchr(str+2,'}'))) {
107 int pl = e-str-2;
108 char pname[pl+1];
109 m_option_t* prop;
110 memcpy(pname,str+2,pl);
111 pname[pl] = 0;
112 if((prop = m_option_list_find(prop_list,pname)) &&
113 (p = m_property_print(prop, ctx)))
114 l = strlen(p), fr = 1;
115 else
116 l = 0;
117 str = e+1;
118 } else if(str[0] == '?' && str[1] == '(' && (e = strchr(str+2,':'))) {
119 int pl = e-str-2;
120 char pname[pl+1];
121 m_option_t* prop;
122 lvl++;
123 if(!skip) {
124 memcpy(pname,str+2,pl);
125 pname[pl] = 0;
126 if(!(prop = m_option_list_find(prop_list,pname)) ||
127 m_property_do(prop,M_PROPERTY_GET,NULL, ctx) < 0)
128 skip = 1, skip_lvl = lvl;
130 str = e+1, l = 0;
131 } else
132 p = str, l = 1, str++;
134 if(skip || l <= 0) continue;
136 if(pos+l+1 > size) {
137 size = pos+l+512;
138 ret = realloc(ret,size);
140 memcpy(ret+pos,p,l);
141 pos += l;
142 if(fr) free(p), fr = 0;
145 ret[pos] = 0;
146 return ret;
149 void m_properties_print_help_list(m_option_t* list) {
150 char min[50],max[50];
151 int i,count = 0;
153 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_PropertyListHeader);
154 for(i = 0 ; list[i].name ; i++) {
155 m_option_t* opt = &list[i];
156 if(opt->flags & M_OPT_MIN)
157 sprintf(min,"%-8.0f",opt->min);
158 else
159 strcpy(min,"No");
160 if(opt->flags & M_OPT_MAX)
161 sprintf(max,"%-8.0f",opt->max);
162 else
163 strcpy(max,"No");
164 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s\n",
165 opt->name,
166 opt->type->name,
167 min,
168 max);
169 count++;
171 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_TotalProperties, count);
174 // Some generic property implementations
176 int m_property_int_ro(m_option_t* prop,int action,
177 void* arg,int var) {
178 switch(action) {
179 case M_PROPERTY_GET:
180 if(!arg) return 0;
181 *(int*)arg = var;
182 return 1;
184 return M_PROPERTY_NOT_IMPLEMENTED;
187 int m_property_int_range(m_option_t* prop,int action,
188 void* arg,int* var) {
189 switch(action) {
190 case M_PROPERTY_SET:
191 if(!arg) return 0;
192 M_PROPERTY_CLAMP(prop,*(int*)arg);
193 *var = *(int*)arg;
194 return 1;
195 case M_PROPERTY_STEP_UP:
196 case M_PROPERTY_STEP_DOWN:
197 *var += (arg ? *(int*)arg : 1) *
198 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
199 M_PROPERTY_CLAMP(prop,*var);
200 return 1;
202 return m_property_int_ro(prop,action,arg,*var);
205 int m_property_choice(m_option_t* prop,int action,
206 void* arg,int* var) {
207 switch(action) {
208 case M_PROPERTY_STEP_UP:
209 case M_PROPERTY_STEP_DOWN:
210 *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max;
211 *var %= (int)prop->max+1;
212 return 1;
214 return m_property_int_range(prop,action,arg,var);
217 int m_property_flag(m_option_t* prop,int action,
218 void* arg,int* var) {
219 switch(action) {
220 case M_PROPERTY_STEP_UP:
221 case M_PROPERTY_STEP_DOWN:
222 *var = *var == prop->min ? prop->max : prop->min;
223 return 1;
224 case M_PROPERTY_PRINT:
225 if(!arg) return 0;
226 *(char**)arg = strdup((*var > prop->min) ? MSGTR_Enabled : MSGTR_Disabled);
227 return 1;
229 return m_property_int_range(prop,action,arg,var);
232 int m_property_float_ro(m_option_t* prop,int action,
233 void* arg,float var) {
234 switch(action) {
235 case M_PROPERTY_GET:
236 if(!arg) return 0;
237 *(float*)arg = var;
238 return 1;
239 case M_PROPERTY_PRINT:
240 if(!arg) return 0;
241 *(char**)arg = malloc(20);
242 sprintf(*(char**)arg,"%.2f",var);
243 return 1;
245 return M_PROPERTY_NOT_IMPLEMENTED;
248 int m_property_float_range(m_option_t* prop,int action,
249 void* arg,float* var) {
250 switch(action) {
251 case M_PROPERTY_SET:
252 if(!arg) return 0;
253 M_PROPERTY_CLAMP(prop,*(float*)arg);
254 *var = *(float*)arg;
255 return 1;
256 case M_PROPERTY_STEP_UP:
257 case M_PROPERTY_STEP_DOWN:
258 *var += (arg ? *(float*)arg : 0.1) *
259 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
260 M_PROPERTY_CLAMP(prop,*var);
261 return 1;
263 return m_property_float_ro(prop,action,arg,*var);
266 int m_property_delay(m_option_t* prop,int action,
267 void* arg,float* var) {
268 switch(action) {
269 case M_PROPERTY_PRINT:
270 if(!arg) return 0;
271 *(char**)arg = malloc(20);
272 sprintf(*(char**)arg,"%d ms",ROUND((*var)*1000));
273 return 1;
274 default:
275 return m_property_float_range(prop,action,arg,var);
279 int m_property_double_ro(m_option_t* prop,int action,
280 void* arg,double var) {
281 switch(action) {
282 case M_PROPERTY_GET:
283 if(!arg) return 0;
284 *(double*)arg = var;
285 return 1;
286 case M_PROPERTY_PRINT:
287 if(!arg) return 0;
288 *(char**)arg = malloc(20);
289 sprintf(*(char**)arg,"%.2f",var);
290 return 1;
292 return M_PROPERTY_NOT_IMPLEMENTED;
295 int m_property_string_ro(m_option_t* prop,int action,void* arg,char* str) {
296 switch(action) {
297 case M_PROPERTY_GET:
298 if(!arg) return 0;
299 *(char**)arg = str;
300 return 1;
301 case M_PROPERTY_PRINT:
302 if(!arg) return 0;
303 *(char**)arg = str ? strdup(str) : NULL;
304 return 1;
306 return M_PROPERTY_NOT_IMPLEMENTED;