subassconvert: do not escape likely ASS override tags
[mplayer.git] / m_property.c
blob2c9f7237b2817f28508976d4a340451b613ad5b6
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 "talloc.h"
31 #include "m_option.h"
32 #include "m_property.h"
33 #include "mp_msg.h"
34 #include "mpcommon.h"
36 static int do_action(const m_option_t *prop_list, const char *name,
37 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)
57 return M_PROPERTY_UNKNOWN;
58 r = ((m_property_ctrl_f)prop->p)(prop, action, arg, ctx);
59 if (action == M_PROPERTY_GET_TYPE && r < 0) {
60 if (!arg)
61 return M_PROPERTY_ERROR;
62 *(const m_option_t **)arg = prop;
63 return M_PROPERTY_OK;
65 return r;
68 int m_property_do(const m_option_t *prop_list, const char *name,
69 int action, void *arg, void *ctx)
71 const m_option_t *opt;
72 void *val;
73 int r;
75 switch (action) {
76 case M_PROPERTY_PRINT:
77 if ((r = do_action(prop_list, name, M_PROPERTY_PRINT, arg, ctx)) >= 0)
78 return r;
79 // fallback on the default print for this type
80 case M_PROPERTY_TO_STRING:
81 if ((r = do_action(prop_list, name, M_PROPERTY_TO_STRING, arg, ctx)) !=
82 M_PROPERTY_NOT_IMPLEMENTED)
83 return r;
84 // fallback on the options API. Get the type, value and print.
85 if ((r =
86 do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
87 return r;
88 val = calloc(1, opt->type->size);
89 if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
90 free(val);
91 return r;
93 if (!arg)
94 return M_PROPERTY_ERROR;
95 char *str = m_option_print(opt, val);
96 free(val);
97 *(char **)arg = str;
98 return str != NULL;
99 case M_PROPERTY_PARSE:
100 // try the property own parsing func
101 if ((r = do_action(prop_list, name, M_PROPERTY_PARSE, arg, ctx)) !=
102 M_PROPERTY_NOT_IMPLEMENTED)
103 return r;
104 // fallback on the options API, get the type and parse.
105 if ((r =
106 do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
107 return r;
108 if (!arg)
109 return M_PROPERTY_ERROR;
110 val = calloc(1, opt->type->size);
111 if ((r = m_option_parse(opt, bstr(opt->name), bstr(arg), false,
112 val)) <= 0) {
113 free(val);
114 return r;
116 r = do_action(prop_list, name, M_PROPERTY_SET, val, ctx);
117 m_option_free(opt, val);
118 free(val);
119 return r;
121 return do_action(prop_list, name, action, arg, ctx);
124 char *m_properties_expand_string(const m_option_t *prop_list, char *str,
125 void *ctx)
127 int l, fr = 0, pos = 0, size = strlen(str) + 512;
128 char *p = NULL, *e, *ret = malloc(size), num_val;
129 int skip = 0, lvl = 0, skip_lvl = 0;
131 while (str[0]) {
132 if (str[0] == '\\') {
133 int sl = 1;
134 switch (str[1]) {
135 case 'e':
136 p = "\x1b", l = 1; break;
137 case 'n':
138 p = "\n", l = 1; break;
139 case 'r':
140 p = "\r", l = 1; break;
141 case 't':
142 p = "\t", l = 1; break;
143 case 'x':
144 if (str[2]) {
145 char num[3] = { str[2], str[3], 0 };
146 char *end = num;
147 num_val = strtol(num, &end, 16);
148 sl = end - num + 1;
149 l = 1;
150 p = &num_val;
151 } else
152 l = 0;
153 break;
154 default:
155 p = str + 1, l = 1;
157 str += 1 + sl;
158 } else if (lvl > 0 && str[0] == ')') {
159 if (skip && lvl <= skip_lvl)
160 skip = 0;
161 lvl--, str++, l = 0;
162 } else if (str[0] == '$' && str[1] == '{'
163 && (e = strchr(str + 2, '}'))) {
164 int pl = e - str - 2;
165 char pname[pl + 1];
166 memcpy(pname, str + 2, pl);
167 pname[pl] = 0;
168 if (m_property_do(prop_list, pname,
169 M_PROPERTY_PRINT, &p, ctx) >= 0 && p)
170 l = strlen(p), fr = 1;
171 else
172 l = 0;
173 str = e + 1;
174 } else if (str[0] == '?' && str[1] == '('
175 && (e = strchr(str + 2, ':'))) {
176 lvl++;
177 if (!skip) {
178 int is_not = str[2] == '!';
179 int pl = e - str - (is_not ? 3 : 2);
180 char pname[pl + 1];
181 memcpy(pname, str + (is_not ? 3 : 2), pl);
182 pname[pl] = 0;
183 if (m_property_do(prop_list, pname, M_PROPERTY_GET, NULL, ctx) < 0) {
184 if (!is_not)
185 skip = 1, skip_lvl = lvl;
186 } else if (is_not)
187 skip = 1, skip_lvl = lvl;
189 str = e + 1, l = 0;
190 } else
191 p = str, l = 1, str++;
193 if (skip || l <= 0)
194 continue;
196 if (pos + l + 1 > size) {
197 size = pos + l + 512;
198 ret = realloc(ret, size);
200 memcpy(ret + pos, p, l);
201 pos += l;
202 if (fr)
203 talloc_free(p), fr = 0;
206 ret[pos] = 0;
207 return ret;
210 void m_properties_print_help_list(const m_option_t *list)
212 char min[50], max[50];
213 int i, count = 0;
215 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO,
216 "\n Name Type Min Max\n\n");
217 for (i = 0; list[i].name; i++) {
218 const m_option_t *opt = &list[i];
219 if (opt->flags & M_OPT_MIN)
220 sprintf(min, "%-8.0f", opt->min);
221 else
222 strcpy(min, "No");
223 if (opt->flags & M_OPT_MAX)
224 sprintf(max, "%-8.0f", opt->max);
225 else
226 strcpy(max, "No");
227 mp_msg(MSGT_CFGPARSER, MSGL_INFO,
228 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
229 opt->name,
230 opt->type->name,
231 min,
232 max);
233 count++;
235 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count);
238 // Some generic property implementations
240 int m_property_int_ro(const m_option_t *prop, int action,
241 void *arg, int var)
243 switch (action) {
244 case M_PROPERTY_GET:
245 if (!arg)
246 return 0;
247 *(int *)arg = var;
248 return 1;
250 return M_PROPERTY_NOT_IMPLEMENTED;
253 int m_property_int_range(const m_option_t *prop, int action,
254 void *arg, int *var)
256 switch (action) {
257 case M_PROPERTY_SET:
258 if (!arg)
259 return 0;
260 M_PROPERTY_CLAMP(prop, *(int *)arg);
261 *var = *(int *)arg;
262 return 1;
263 case M_PROPERTY_STEP:
264 *var += (arg ? *(int *)arg : 1);
265 M_PROPERTY_CLAMP(prop, *var);
266 return 1;
268 return m_property_int_ro(prop, action, arg, *var);
271 int m_property_choice(const m_option_t *prop, int action,
272 void *arg, int *var)
274 switch (action) {
275 case M_PROPERTY_STEP:
276 *var += (!arg || *(int *)arg >= 0) ? 1 : prop->max;
277 *var %= (int)prop->max + 1;
278 return 1;
280 return m_property_int_range(prop, action, arg, var);
283 int m_property_flag_ro(const m_option_t *prop, int action,
284 void *arg, int var)
286 switch (action) {
287 case M_PROPERTY_PRINT:
288 if (!arg)
289 return 0;
290 *(char **)arg = talloc_strdup(NULL, (var > prop->min) ?
291 mp_gtext("enabled") : mp_gtext("disabled"));
292 return 1;
294 return m_property_int_ro(prop, action, arg, var);
297 int m_property_flag(const m_option_t *prop, int action,
298 void *arg, int *var)
300 switch (action) {
301 case M_PROPERTY_STEP:
302 *var = *var == prop->min ? prop->max : prop->min;
303 return 1;
304 case M_PROPERTY_PRINT:
305 return m_property_flag_ro(prop, action, arg, *var);
307 return m_property_int_range(prop, action, arg, var);
310 int m_property_float_ro(const m_option_t *prop, int action,
311 void *arg, float var)
313 switch (action) {
314 case M_PROPERTY_GET:
315 if (!arg)
316 return 0;
317 *(float *)arg = var;
318 return 1;
319 case M_PROPERTY_PRINT:
320 if (!arg)
321 return 0;
322 *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
323 return 1;
325 return M_PROPERTY_NOT_IMPLEMENTED;
328 int m_property_float_range(const m_option_t *prop, int action,
329 void *arg, float *var)
331 switch (action) {
332 case M_PROPERTY_SET:
333 if (!arg)
334 return 0;
335 M_PROPERTY_CLAMP(prop, *(float *)arg);
336 *var = *(float *)arg;
337 return 1;
338 case M_PROPERTY_STEP:
339 *var += (arg ? *(float *)arg : 0.1);
340 M_PROPERTY_CLAMP(prop, *var);
341 return 1;
343 return m_property_float_ro(prop, action, arg, *var);
346 int m_property_delay(const m_option_t *prop, int action,
347 void *arg, float *var)
349 switch (action) {
350 case M_PROPERTY_PRINT:
351 if (!arg)
352 return 0;
353 *(char **)arg = talloc_asprintf(NULL, "%d ms", ROUND((*var) * 1000));
354 return 1;
355 default:
356 return m_property_float_range(prop, action, arg, var);
360 int m_property_double_ro(const m_option_t *prop, int action,
361 void *arg, double var)
363 switch (action) {
364 case M_PROPERTY_GET:
365 if (!arg)
366 return 0;
367 *(double *)arg = var;
368 return 1;
369 case M_PROPERTY_PRINT:
370 if (!arg)
371 return 0;
372 *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
373 return 1;
375 return M_PROPERTY_NOT_IMPLEMENTED;
378 static char *format_time(double time)
380 int h, m, s = time;
381 h = s / 3600;
382 s -= h * 3600;
383 m = s / 60;
384 s -= m * 60;
385 return talloc_asprintf(NULL, "%02d:%02d:%02d", h, m, s);
388 int m_property_time_ro(const m_option_t *prop, int action,
389 void *arg, double var)
391 switch (action) {
392 case M_PROPERTY_PRINT:
393 if (!arg)
394 return M_PROPERTY_ERROR;
395 else {
396 *(char **)arg = format_time(var);
397 return M_PROPERTY_OK;
400 return m_property_double_ro(prop, action, arg, var);
403 int m_property_string_ro(const m_option_t *prop, int action, void *arg,
404 char *str)
406 switch (action) {
407 case M_PROPERTY_GET:
408 if (!arg)
409 return 0;
410 *(char **)arg = str;
411 return 1;
412 case M_PROPERTY_PRINT:
413 if (!arg)
414 return 0;
415 *(char **)arg = talloc_strdup(NULL, str);
416 return 1;
418 return M_PROPERTY_NOT_IMPLEMENTED;
421 int m_property_bitrate(const m_option_t *prop, int action, void *arg, int rate)
423 switch (action) {
424 case M_PROPERTY_PRINT:
425 if (!arg)
426 return M_PROPERTY_ERROR;
427 *(char **)arg = talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
428 return M_PROPERTY_OK;
430 return m_property_int_ro(prop, action, arg, rate);