~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to m_option.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:45:33 UTC
  • Revision ID: siretart@tauware.de-20060708084533-dbc155bde7122e78
imported mplayer_0.99+1.0pre7try2+cvs20060117

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "config.h"
 
2
 
 
3
#include <stdlib.h>
 
4
#include <string.h>
 
5
#include <math.h>
 
6
#include <stdio.h>
 
7
#include <stdarg.h>
 
8
#include <inttypes.h>
 
9
#include <unistd.h>
 
10
 
 
11
#include "m_option.h"
 
12
//#include "m_config.h"
 
13
#include "mp_msg.h"
 
14
#include "libmpdemux/url.h"
 
15
 
 
16
// Don't free for 'production' atm
 
17
#ifndef MP_DEBUG
 
18
//#define NO_FREE
 
19
#endif
 
20
 
 
21
m_option_t* m_option_list_find(m_option_t* list,char* name) {
 
22
  int i;
 
23
 
 
24
  for(i = 0 ; list[i].name ; i++) {
 
25
    int l = strlen(list[i].name) - 1;
 
26
    if((list[i].type->flags & M_OPT_TYPE_ALLOW_WILDCARD) &&
 
27
       (l > 0) && (list[i].name[l] == '*')) {
 
28
      if(strncasecmp(list[i].name,name,l) == 0)
 
29
        return &list[i];
 
30
    } else if(strcasecmp(list[i].name,name) == 0)
 
31
      return &list[i];
 
32
  }
 
33
  return NULL;
 
34
}
 
35
 
 
36
// Default function that just does a memcpy
 
37
 
 
38
static void copy_opt(m_option_t* opt,void* dst,void* src) {
 
39
  if(dst && src)
 
40
    memcpy(dst,src,opt->type->size);
 
41
}
 
42
 
 
43
// Helper for the print funcs (from man printf)
 
44
static char* dup_printf(const char *fmt, ...) {       
 
45
  /* Guess we need no more than 50 bytes. */
 
46
  int n, size = 50;
 
47
  char *p;
 
48
  va_list ap;
 
49
  if ((p = malloc (size)) == NULL)
 
50
    return NULL;
 
51
  while (1) {
 
52
    /* Try to print in the allocated space. */
 
53
    va_start(ap, fmt);
 
54
    n = vsnprintf (p, size, fmt, ap);
 
55
    va_end(ap);
 
56
    /* If that worked, return the string. */
 
57
    if (n > -1 && n < size)      
 
58
      return p;
 
59
    /* Else try again with more space. */
 
60
    if (n > -1)    /* glibc 2.1 */
 
61
      size = n+1; /* precisely what is needed */
 
62
    else           /* glibc 2.0 */
 
63
      size *= 2;  /* twice the old size */
 
64
    if ((p = realloc (p, size)) == NULL)
 
65
      return NULL;
 
66
  }
 
67
}
 
68
 
 
69
 
 
70
// Flag
 
71
 
 
72
#define VAL(x) (*(int*)(x))
 
73
 
 
74
static int parse_flag(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
75
  if (src == M_CONFIG_FILE) {
 
76
    if(!param) return M_OPT_MISSING_PARAM;
 
77
    if (!strcasecmp(param, "yes") ||    /* any other language? */
 
78
        !strcasecmp(param, "on") ||
 
79
        !strcasecmp(param, "ja") ||
 
80
        !strcasecmp(param, "si") ||
 
81
        !strcasecmp(param, "igen") ||
 
82
        !strcasecmp(param, "y") ||
 
83
        !strcasecmp(param, "j") ||
 
84
        !strcasecmp(param, "i") ||
 
85
        !strcasecmp(param, "tak") ||
 
86
        !strcasecmp(param, "ja") ||
 
87
        !strcasecmp(param, "true") ||
 
88
        !strcmp(param, "1")) {
 
89
      if(dst) VAL(dst) = opt->max;
 
90
    } else if (!strcasecmp(param, "no") ||
 
91
               !strcasecmp(param, "off") ||
 
92
               !strcasecmp(param, "nein") ||
 
93
               !strcasecmp(param, "nicht") ||
 
94
               !strcasecmp(param, "nem") ||
 
95
               !strcasecmp(param, "n") ||
 
96
               !strcasecmp(param, "nie") ||
 
97
               !strcasecmp(param, "nej") ||
 
98
               !strcasecmp(param, "false") ||
 
99
               !strcmp(param, "0")) {
 
100
      if(dst) VAL(dst) = opt->min;
 
101
    } else {
 
102
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid parameter for %s flag: %s\n",name, param);
 
103
      return M_OPT_INVALID;
 
104
    }
 
105
    return 1;
 
106
  } else {
 
107
    if(dst) VAL(dst) = opt->max;
 
108
    return 0;
 
109
  }
 
110
}
 
111
 
 
112
static char* print_flag(m_option_t* opt,  void* val) {
 
113
  if(VAL(val) == opt->min)
 
114
    return strdup("no");
 
115
  else
 
116
    return strdup("yes");
 
117
}
 
118
 
 
119
m_option_type_t m_option_type_flag = {
 
120
  "Flag",
 
121
  "need yes or no in config files",
 
122
  sizeof(int),
 
123
  0,
 
124
  parse_flag,
 
125
  print_flag,
 
126
  copy_opt,
 
127
  copy_opt,
 
128
  NULL,
 
129
  NULL
 
130
};
 
131
 
 
132
// Integer
 
133
 
 
134
static int parse_int(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
135
  long tmp_int;
 
136
  char *endptr;
 
137
  src = 0;
 
138
 
 
139
  if (param == NULL)
 
140
    return M_OPT_MISSING_PARAM;
 
141
 
 
142
  tmp_int = strtol(param, &endptr, 0);
 
143
  if (*endptr) {
 
144
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",name, param);
 
145
    return M_OPT_INVALID;
 
146
  }
 
147
 
 
148
  if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) {
 
149
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %d: %s\n", name, (int) opt->min, param);
 
150
    return M_OPT_OUT_OF_RANGE;
 
151
  }
 
152
 
 
153
  if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) {
 
154
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %d: %s\n",name, (int) opt->max, param);
 
155
    return M_OPT_OUT_OF_RANGE;
 
156
  }
 
157
 
 
158
  if(dst) VAL(dst) = tmp_int;
 
159
 
 
160
  return 1;
 
161
}
 
162
 
 
163
static char* print_int(m_option_t* opt,  void* val) {
 
164
  opt = NULL;
 
165
  return dup_printf("%d",VAL(val));
 
166
}
 
167
 
 
168
m_option_type_t m_option_type_int = {
 
169
  "Integer",
 
170
  "",
 
171
  sizeof(int),
 
172
  0,
 
173
  parse_int,
 
174
  print_int,
 
175
  copy_opt,
 
176
  copy_opt,
 
177
  NULL,
 
178
  NULL
 
179
};
 
180
 
 
181
// Float
 
182
 
 
183
#undef VAL
 
184
#define VAL(x) (*(double*)(x))
 
185
 
 
186
static int parse_double(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
187
  double tmp_float;
 
188
  char* endptr;
 
189
  src = 0;
 
190
 
 
191
  if (param == NULL)
 
192
    return M_OPT_MISSING_PARAM;
 
193
 
 
194
  tmp_float = strtod(param, &endptr);
 
195
 
 
196
  switch(*endptr) {
 
197
  case ':':
 
198
  case '/':
 
199
    tmp_float /= strtod(endptr+1, &endptr);
 
200
    break;
 
201
  case '.':
 
202
  case ',':
 
203
    /* we also handle floats specified with
 
204
     * non-locale decimal point ::atmos
 
205
     */
 
206
    if(tmp_float<0)
 
207
      tmp_float -= 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
 
208
    else
 
209
      tmp_float += 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
 
210
    break;
 
211
  }
 
212
 
 
213
  if (*endptr) {
 
214
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be a floating point "
 
215
           "number or a ratio (numerator[:/]denominator): %s\n",name, param);
 
216
    return M_OPT_INVALID;
 
217
  }
 
218
 
 
219
  if (opt->flags & M_OPT_MIN)
 
220
    if (tmp_float < opt->min) {
 
221
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %f: %s\n", name, opt->min, param);
 
222
      return M_OPT_OUT_OF_RANGE;
 
223
    }
 
224
 
 
225
  if (opt->flags & M_OPT_MAX)
 
226
    if (tmp_float > opt->max) {
 
227
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %f: %s\n", name, opt->max, param);
 
228
      return M_OPT_OUT_OF_RANGE;
 
229
    }
 
230
 
 
231
  if(dst) VAL(dst) = tmp_float;
 
232
  return 1;
 
233
}
 
234
 
 
235
static char* print_double(m_option_t* opt,  void* val) {
 
236
  opt = NULL;
 
237
  return dup_printf("%f",VAL(val));
 
238
}
 
239
 
 
240
m_option_type_t m_option_type_double = {
 
241
  "Double",
 
242
  "double precission floating point number or ratio (numerator[:/]denominator)",
 
243
  sizeof(double),
 
244
  0,
 
245
  parse_double,
 
246
  print_double,
 
247
  copy_opt,
 
248
  copy_opt,
 
249
  NULL,
 
250
  NULL
 
251
};
 
252
 
 
253
#undef VAL
 
254
#define VAL(x) (*(float*)(x))
 
255
 
 
256
static int parse_float(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
257
    double tmp;
 
258
    int r= parse_double(opt, name, param, &tmp, src);
 
259
    if(r==1 && dst) VAL(dst) = tmp;
 
260
    return r;
 
261
}
 
262
 
 
263
static char* print_float(m_option_t* opt,  void* val) {
 
264
  opt = NULL;
 
265
  return dup_printf("%f",VAL(val));
 
266
}
 
267
 
 
268
m_option_type_t m_option_type_float = {
 
269
  "Float",
 
270
  "floating point number or ratio (numerator[:/]denominator)",
 
271
  sizeof(float),
 
272
  0,
 
273
  parse_float,
 
274
  print_float,
 
275
  copy_opt,
 
276
  copy_opt,
 
277
  NULL,
 
278
  NULL
 
279
};
 
280
 
 
281
///////////// Position
 
282
#undef VAL
 
283
#define VAL(x) (*(off_t*)(x))
 
284
 
 
285
static int parse_position(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
286
  off_t tmp_off;
 
287
  char dummy;
 
288
 
 
289
  if (param == NULL)
 
290
    return M_OPT_MISSING_PARAM;
 
291
  if (sscanf(param, sizeof(off_t) == sizeof(int) ?
 
292
             "%d%c" : "%"PRId64"%c", &tmp_off, &dummy) != 1) {
 
293
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",opt->name,param);
 
294
    return M_OPT_INVALID;
 
295
  }
 
296
 
 
297
  if (opt->flags & M_OPT_MIN)
 
298
    if (tmp_off < opt->min) {
 
299
      mp_msg(MSGT_CFGPARSER, MSGL_ERR,
 
300
              "The %s option must be >= %"PRId64": %s\n",
 
301
             name, (int64_t) opt->min, param);
 
302
      return M_OPT_OUT_OF_RANGE;
 
303
    }
 
304
 
 
305
  if (opt->flags & M_OPT_MAX)
 
306
    if (tmp_off > opt->max) {
 
307
      mp_msg(MSGT_CFGPARSER, MSGL_ERR,
 
308
              "The %s option must be <= %"PRId64": %s\n",
 
309
             name, (int64_t) opt->max, param);
 
310
      return M_OPT_OUT_OF_RANGE;
 
311
    }
 
312
 
 
313
  if(dst)
 
314
    VAL(dst) = tmp_off;
 
315
  return 1;
 
316
}
 
317
 
 
318
static char* print_position(m_option_t* opt,  void* val) {
 
319
  return dup_printf("%"PRId64,(int64_t)VAL(val));
 
320
}
 
321
 
 
322
m_option_type_t m_option_type_position = {
 
323
  "Position",
 
324
  "Integer (off_t)",
 
325
  sizeof(off_t),
 
326
  0,
 
327
  parse_position,
 
328
  print_position,
 
329
  copy_opt,
 
330
  copy_opt,
 
331
  NULL,
 
332
  NULL
 
333
};
 
334
 
 
335
 
 
336
///////////// String
 
337
 
 
338
#undef VAL
 
339
#define VAL(x) (*(char**)(x))
 
340
 
 
341
static int parse_str(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
342
  
 
343
 
 
344
  if (param == NULL)
 
345
      return M_OPT_MISSING_PARAM;
 
346
 
 
347
  if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) {
 
348
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be >= %d chars: %s\n",
 
349
           (int) opt->min, param);
 
350
    return M_OPT_OUT_OF_RANGE;
 
351
  }
 
352
 
 
353
  if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) {
 
354
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Parameter must be <= %d chars: %s\n",
 
355
           (int) opt->max, param);
 
356
    return M_OPT_OUT_OF_RANGE;
 
357
  }
 
358
 
 
359
  if(dst) {
 
360
    if(VAL(dst))
 
361
      free(VAL(dst));
 
362
    VAL(dst) = strdup(param);
 
363
  }
 
364
 
 
365
  return 1;
 
366
 
 
367
}
 
368
 
 
369
static char* print_str(m_option_t* opt,  void* val) {
 
370
  return (val && VAL(val) && strlen(VAL(val)) > 0) ? strdup(VAL(val)) : NULL;
 
371
}
 
372
 
 
373
static void copy_str(m_option_t* opt,void* dst, void* src) {
 
374
  if(dst && src) {
 
375
#ifndef NO_FREE
 
376
    if(VAL(dst)) free(VAL(dst)); //FIXME!!!
 
377
#endif
 
378
    VAL(dst) = VAL(src) ? strdup(VAL(src)) : NULL;
 
379
  }
 
380
}
 
381
  
 
382
static void free_str(void* src) {
 
383
  if(src && VAL(src)){
 
384
#ifndef NO_FREE
 
385
    free(VAL(src)); //FIXME!!!
 
386
#endif
 
387
    VAL(src) = NULL;
 
388
  }
 
389
}
 
390
 
 
391
m_option_type_t m_option_type_string = {
 
392
  "String",
 
393
  "",
 
394
  sizeof(char*),
 
395
  M_OPT_TYPE_DYNAMIC,
 
396
  parse_str,
 
397
  print_str,
 
398
  copy_str,
 
399
  copy_str,
 
400
  copy_str,
 
401
  free_str
 
402
};
 
403
  
 
404
//////////// String list
 
405
 
 
406
#define LIST_SEPARATOR ','
 
407
#undef VAL
 
408
#define VAL(x) (*(char***)(x))
 
409
 
 
410
#define OP_NONE 0
 
411
#define OP_ADD 1
 
412
#define OP_PRE 2
 
413
#define OP_DEL 3
 
414
#define OP_CLR 4
 
415
 
 
416
static void free_str_list(void* dst) {
 
417
  char** d;
 
418
  int i;
 
419
 
 
420
  if(!dst || !VAL(dst)) return;
 
421
  d = VAL(dst);
 
422
 
 
423
// FIXME!!!
 
424
#ifndef NO_FREE
 
425
  for(i = 0 ; d[i] != NULL ; i++)
 
426
    free(d[i]);
 
427
  free(d);
 
428
#endif
 
429
  VAL(dst) = NULL;
 
430
}
 
431
 
 
432
static int str_list_add(char** add, int n,void* dst,int pre) {
 
433
  char** lst = VAL(dst);
 
434
  int ln;
 
435
 
 
436
  if(!dst) return M_OPT_PARSER_ERR;
 
437
  lst = VAL(dst);
 
438
 
 
439
  for(ln = 0 ; lst && lst[ln] ; ln++)
 
440
    /**/;
 
441
 
 
442
  lst = realloc(lst,(n+ln+1)*sizeof(char*));
 
443
  
 
444
  if(pre) {
 
445
    memmove(&lst[n],lst,(ln+1)*sizeof(char*));
 
446
    memcpy(lst,add,n*sizeof(char*));
 
447
  } else 
 
448
    memcpy(&lst[ln],add,(n+1)*sizeof(char*));
 
449
 
 
450
  free(add);
 
451
 
 
452
  VAL(dst) = lst;
 
453
  
 
454
  return 1;
 
455
}
 
456
 
 
457
static int str_list_del(char** del, int n,void* dst) {
 
458
  char **lst,*ep,**d;
 
459
  int i,ln,s;
 
460
  long idx;
 
461
  
 
462
  if(!dst) return M_OPT_PARSER_ERR;
 
463
  lst = VAL(dst);
 
464
 
 
465
  for(ln = 0 ; lst && lst[ln] ; ln++)
 
466
    /**/;
 
467
  s = ln;
 
468
 
 
469
  for(i = 0 ; del[i] != NULL ; i++) {
 
470
    idx = strtol(del[i], &ep, 0);
 
471
    if(*ep) {
 
472
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n",del[i]);
 
473
      free(del[i]);
 
474
      continue;
 
475
    }
 
476
    free(del[i]);
 
477
    if(idx < 0 || idx >= ln) {
 
478
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Index %ld is out of range.\n",idx);
 
479
      continue;
 
480
    } else if(!lst[idx])
 
481
      continue;
 
482
    free(lst[idx]);
 
483
    lst[idx] = NULL;
 
484
    s--;
 
485
  }
 
486
  free(del);
 
487
 
 
488
  if(s == 0) {
 
489
    if(lst) free(lst);
 
490
    VAL(dst) = NULL;
 
491
    return 1;
 
492
  }
 
493
 
 
494
  d = calloc(s+1,sizeof(char*));
 
495
  for(i = 0, n = 0 ; i < ln ; i++) {
 
496
    if(!lst[i]) continue;
 
497
    d[n] = lst[i];
 
498
    n++;
 
499
  }
 
500
  d[s] = NULL;
 
501
 
 
502
  if(lst) free(lst);
 
503
  VAL(dst) = d;
 
504
 
 
505
  return 1;
 
506
}
 
507
  
 
508
 
 
509
static int parse_str_list(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
510
  int n = 0,len = strlen(opt->name);
 
511
  char *ptr = param, *last_ptr, **res;
 
512
  int op = OP_NONE;
 
513
 
 
514
  if(opt->name[len-1] == '*' && ((int)strlen(name) > len - 1)) {
 
515
    char* n = &name[len-1];
 
516
    if(strcasecmp(n,"-add") == 0)
 
517
      op = OP_ADD;
 
518
    else if(strcasecmp(n,"-pre") == 0)
 
519
      op = OP_PRE;
 
520
    else if(strcasecmp(n,"-del") == 0)
 
521
      op = OP_DEL;
 
522
    else if(strcasecmp(n,"-clr") == 0)
 
523
      op = OP_CLR;
 
524
    else
 
525
      return M_OPT_UNKNOWN;
 
526
  }
 
527
 
 
528
  // Clear the list ??
 
529
  if(op == OP_CLR) {
 
530
    if(dst)
 
531
      free_str_list(dst);
 
532
    return 0;
 
533
  }
 
534
 
 
535
  // All other ops need a param
 
536
  if (param == NULL || strlen(param) == 0)
 
537
      return M_OPT_MISSING_PARAM;
 
538
 
 
539
 
 
540
  while(ptr[0] != '\0') {
 
541
    last_ptr = ptr;
 
542
    ptr = strchr(ptr,LIST_SEPARATOR);
 
543
    if(!ptr) {
 
544
      n++;
 
545
      break;
 
546
    }
 
547
    ptr++;
 
548
    n++;
 
549
  }
 
550
  if(n == 0)
 
551
    return M_OPT_INVALID;
 
552
  if( ((opt->flags & M_OPT_MIN) && (n < opt->min)) || 
 
553
      ((opt->flags & M_OPT_MAX) && (n > opt->max)) )
 
554
    return M_OPT_OUT_OF_RANGE;
 
555
 
 
556
  if(!dst) return 1;
 
557
 
 
558
  res = malloc((n+2)*sizeof(char*));
 
559
  ptr = param;
 
560
  n = 0;
 
561
 
 
562
  while(1) {
 
563
    last_ptr = ptr;
 
564
    ptr = strchr(ptr,LIST_SEPARATOR);
 
565
    if(!ptr) {
 
566
      res[n] = strdup(last_ptr);
 
567
      n++;
 
568
      break;
 
569
    }
 
570
    len = ptr - last_ptr;
 
571
    res[n] = (char*)malloc(len + 1);
 
572
    if(len) strncpy(res[n],last_ptr,len);
 
573
    res[n][len] = '\0';
 
574
    ptr++;
 
575
    n++;
 
576
  }
 
577
  res[n] = NULL;
 
578
 
 
579
  switch(op) {
 
580
  case OP_ADD:
 
581
    return str_list_add(res,n,dst,0);
 
582
  case OP_PRE:
 
583
    return str_list_add(res,n,dst,1);
 
584
  case OP_DEL:
 
585
    return str_list_del(res,n,dst);
 
586
  }
 
587
 
 
588
  if(VAL(dst))
 
589
    free_str_list(dst);
 
590
  VAL(dst) = res;
 
591
 
 
592
  return 1;
 
593
}
 
594
  
 
595
static void copy_str_list(m_option_t* opt,void* dst, void* src) {
 
596
  int n;
 
597
  char **d,**s;
 
598
 
 
599
  if(!(dst && src)) return;
 
600
  s = VAL(src);
 
601
 
 
602
  if(VAL(dst))
 
603
    free_str_list(dst);
 
604
 
 
605
  if(!s) {
 
606
    VAL(dst) = NULL;
 
607
    return;
 
608
  }
 
609
 
 
610
  for(n = 0 ; s[n] != NULL ; n++)
 
611
    /* NOTHING */;
 
612
  d = (char**)malloc((n+1)*sizeof(char*));
 
613
  for( ; n >= 0 ; n--)
 
614
    d[n] = s[n] ? strdup(s[n]) : NULL;
 
615
 
 
616
  VAL(dst) = d;
 
617
}
 
618
 
 
619
static char* print_str_list(m_option_t* opt, void* src) {
 
620
  char **lst = NULL;
 
621
  char *ret = NULL,*last = NULL;
 
622
  int i;
 
623
  
 
624
  if(!(src && VAL(src))) return NULL;
 
625
  lst = VAL(src);
 
626
 
 
627
  for(i = 0 ; lst[i] ; i++) {
 
628
    if(last) {
 
629
      ret = dup_printf("%s,%s",last,lst[i]);
 
630
      free(last);
 
631
    } else
 
632
      ret = strdup(lst[i]);
 
633
    last = ret;
 
634
  }
 
635
  if(last && last != ret) free(last);
 
636
  return ret;
 
637
}
 
638
 
 
639
m_option_type_t m_option_type_string_list = {
 
640
  "String list",
 
641
  "A list of strings separated by ','\n"
 
642
  "Option with a name ending in an * permits using the following suffix: \n"
 
643
  "\t-add: Add the given parameters at the end of the list.\n"
 
644
  "\t-pre: Add the given parameters at the begining of the list.\n"
 
645
  "\t-del: Remove the entry at the given indices.\n"
 
646
  "\t-clr: Clear the list.\n"
 
647
  "e.g: -vf-add flip,mirror -vf-del 2,5\n",  
 
648
  sizeof(char**),
 
649
  M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
 
650
  parse_str_list,
 
651
  print_str_list,
 
652
  copy_str_list,
 
653
  copy_str_list,
 
654
  copy_str_list,
 
655
  free_str_list
 
656
};
 
657
 
 
658
 
 
659
///////////////////  Func based options
 
660
 
 
661
// A chained list to save the various calls for func_param and func_full
 
662
typedef struct m_func_save m_func_save_t;
 
663
struct m_func_save {
 
664
  m_func_save_t* next;
 
665
  char* name;
 
666
  char* param;
 
667
};
 
668
 
 
669
#undef VAL
 
670
#define VAL(x) (*(m_func_save_t**)(x))
 
671
 
 
672
static void free_func_pf(void* src) {
 
673
  m_func_save_t *s,*n;
 
674
 
 
675
  if(!src) return;
 
676
 
 
677
  s = VAL(src);
 
678
  
 
679
  while(s) {
 
680
    n = s->next;
 
681
    free(s->name);
 
682
    if(s->param) free(s->param);
 
683
    free(s);
 
684
    s = n;
 
685
  }
 
686
  VAL(src) = NULL;
 
687
}
 
688
 
 
689
// Parser for func_param and func_full
 
690
static int parse_func_pf(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
691
  m_func_save_t *s,*p;
 
692
 
 
693
  if(!dst)
 
694
    return 1;
 
695
 
 
696
  s = (m_func_save_t*)calloc(1,sizeof(m_func_save_t));
 
697
  s->name = strdup(name);
 
698
  s->param = param ? strdup(param) : NULL;
 
699
 
 
700
  p = VAL(dst);
 
701
  if(p) {
 
702
    for( ; p->next != NULL ; p = p->next)
 
703
      /**/;
 
704
    p->next = s;
 
705
  } else
 
706
    VAL(dst) = s;
 
707
 
 
708
  return 1;
 
709
}
 
710
 
 
711
static void copy_func_pf(m_option_t* opt,void* dst, void* src) {
 
712
  m_func_save_t *d = NULL, *s,* last = NULL;
 
713
 
 
714
  if(!(dst && src)) return;
 
715
  s = VAL(src);
 
716
 
 
717
  if(VAL(dst))
 
718
    free_func_pf(dst);
 
719
 
 
720
  while(s) {
 
721
    d = (m_func_save_t*)malloc(sizeof(m_func_save_t));
 
722
    d->name = strdup(s->name);
 
723
    d->param = s->param ? strdup(s->param) : NULL;
 
724
    if(last)
 
725
      last->next = d;
 
726
    else
 
727
      VAL(dst) = d;
 
728
    last = d;
 
729
    s = s->next;
 
730
  }
 
731
  
 
732
    
 
733
}
 
734
 
 
735
/////////////////// Func_param
 
736
 
 
737
static void set_func_param(m_option_t* opt, void* dst, void* src) {
 
738
  m_func_save_t* s;
 
739
 
 
740
  if(!src) return;
 
741
  s = VAL(src);
 
742
  
 
743
  if(!s) return;
 
744
 
 
745
  // Revert if needed
 
746
  if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
 
747
  for( ; s != NULL ; s = s->next)
 
748
    ((m_opt_func_param_t) opt->p)(opt,s->param);
 
749
}
 
750
 
 
751
m_option_type_t m_option_type_func_param = {
 
752
  "Func param",
 
753
  "",
 
754
  sizeof(m_func_save_t*),
 
755
  M_OPT_TYPE_INDIRECT,
 
756
  parse_func_pf,
 
757
  NULL,
 
758
  NULL, // Nothing to do on save
 
759
  set_func_param,
 
760
  copy_func_pf,
 
761
  free_func_pf
 
762
};
 
763
 
 
764
/////////////////// Func_full
 
765
 
 
766
static void set_func_full(m_option_t* opt, void* dst, void* src) {
 
767
  m_func_save_t* s;
 
768
 
 
769
  if(!src) return;
 
770
 
 
771
  for(s = VAL(src) ; s ; s = s->next) {
 
772
    // Revert if needed
 
773
    if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,s->name);
 
774
    ((m_opt_func_full_t) opt->p)(opt,s->name,s->param);
 
775
  }
 
776
}
 
777
 
 
778
m_option_type_t m_option_type_func_full = {
 
779
  "Func full",
 
780
  "",
 
781
  sizeof(m_func_save_t*),
 
782
  M_OPT_TYPE_ALLOW_WILDCARD|M_OPT_TYPE_INDIRECT,
 
783
  parse_func_pf,
 
784
  NULL,
 
785
  NULL, // Nothing to do on save
 
786
  set_func_full,
 
787
  copy_func_pf,
 
788
  free_func_pf
 
789
};
 
790
 
 
791
/////////////// Func
 
792
 
 
793
#undef VAL
 
794
#define VAL(x) (*(int*)(x))
 
795
 
 
796
static int parse_func(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
797
  if(dst)
 
798
    VAL(dst) += 1;
 
799
  return 0;
 
800
}
 
801
 
 
802
static void set_func(m_option_t* opt,void* dst, void* src) {
 
803
  int i;
 
804
  if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
 
805
  for(i = 0 ; i < VAL(src) ; i++)
 
806
    ((m_opt_func_t) opt->p)(opt);
 
807
}
 
808
 
 
809
m_option_type_t m_option_type_func = {
 
810
  "Func",
 
811
  "",
 
812
  sizeof(int),
 
813
  M_OPT_TYPE_INDIRECT,
 
814
  parse_func,
 
815
  NULL,
 
816
  NULL, // Nothing to do on save
 
817
  set_func,
 
818
  NULL,
 
819
  NULL
 
820
};
 
821
 
 
822
/////////////////// Print
 
823
 
 
824
static int parse_print(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
825
  if(opt->type->flags&M_OPT_TYPE_INDIRECT)
 
826
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) opt->p);
 
827
  else
 
828
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", (char *) opt->p);
 
829
 
 
830
  if(opt->priv == NULL)
 
831
    return M_OPT_EXIT;
 
832
  return 1;
 
833
}
 
834
 
 
835
m_option_type_t m_option_type_print = {
 
836
  "Print",
 
837
  "",
 
838
  0,
 
839
  0,
 
840
  parse_print,
 
841
  NULL,
 
842
  NULL,
 
843
  NULL,
 
844
  NULL,
 
845
  NULL
 
846
};
 
847
 
 
848
m_option_type_t m_option_type_print_indirect = {
 
849
  "Print",
 
850
  "",
 
851
  0,
 
852
  M_OPT_TYPE_INDIRECT,
 
853
  parse_print,
 
854
  NULL,
 
855
  NULL,
 
856
  NULL,
 
857
  NULL,
 
858
  NULL
 
859
};
 
860
 
 
861
 
 
862
/////////////////////// Subconfig
 
863
#undef VAL
 
864
#define VAL(x) (*(char***)(x))
 
865
 
 
866
static int parse_subconf(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
867
  char *subparam;
 
868
  char *subopt;
 
869
  int nr = 0,i,r;
 
870
  m_option_t *subopts;
 
871
  char *p;
 
872
  char** lst = NULL;
 
873
 
 
874
  if (param == NULL || strlen(param) == 0)
 
875
    return M_OPT_MISSING_PARAM;
 
876
 
 
877
  subparam = malloc(strlen(param)+1);
 
878
  subopt = malloc(strlen(param)+1);
 
879
  p = param;
 
880
 
 
881
  subopts = opt->p;
 
882
 
 
883
  while(p[0])
 
884
    {
 
885
      int sscanf_ret = 1;
 
886
      int optlen = strcspn(p, ":=");
 
887
      /* clear out */
 
888
      subopt[0] = subparam[0] = 0;
 
889
      strlcpy(subopt, p, optlen + 1);
 
890
      p = &p[optlen];
 
891
      if (p[0] == '=') {
 
892
        sscanf_ret = 2;
 
893
        p = &p[1];
 
894
        if (p[0] == '"') {
 
895
          p = &p[1];
 
896
          optlen = strcspn(p, "\"");
 
897
          strlcpy(subparam, p, optlen + 1);
 
898
          p = &p[optlen];
 
899
          if (p[0] != '"') {
 
900
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Terminating '\"' missing for '%s'\n", subopt);
 
901
            return M_OPT_INVALID;
 
902
          }
 
903
          p = &p[1];
 
904
        } else if (p[0] == '%') {
 
905
          p = &p[1];
 
906
          optlen = (int)strtol(p, &p, 0);
 
907
          if (!p || p[0] != '%' || (optlen > strlen(p) - 1)) {
 
908
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid length %i for '%s'\n", optlen, subopt);
 
909
            return M_OPT_INVALID;
 
910
          }
 
911
          p = &p[1];
 
912
          strlcpy(subparam, p, optlen + 1);
 
913
          p = &p[optlen];
 
914
        } else {
 
915
          optlen = strcspn(p, ":");
 
916
          strlcpy(subparam, p, optlen + 1);
 
917
          p = &p[optlen];
 
918
        }
 
919
      }
 
920
      if (p[0] == ':')
 
921
        p = &p[1];
 
922
      else if (p[0]) {
 
923
        mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Incorrect termination for '%s'\n", subopt);
 
924
        return M_OPT_INVALID;
 
925
      }
 
926
                            
 
927
      switch(sscanf_ret)
 
928
        {
 
929
        case 1:
 
930
          subparam[0] = 0;
 
931
        case 2:
 
932
          for(i = 0 ; subopts[i].name ; i++) {
 
933
            if(!strcmp(subopts[i].name,subopt)) break;
 
934
          }
 
935
          if(!subopts[i].name) {
 
936
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Unknown suboption %s\n",name,subopt);
 
937
            return M_OPT_UNKNOWN;
 
938
          }
 
939
          r = m_option_parse(&subopts[i],subopt,
 
940
                             subparam[0] == 0 ? NULL : subparam,NULL,src);
 
941
          if(r < 0) return r;
 
942
          if(dst) {
 
943
            lst = (char**)realloc(lst,2 * (nr+2) * sizeof(char*));
 
944
            lst[2*nr] = strdup(subopt);
 
945
            lst[2*nr+1] = subparam[0] == 0 ? NULL : strdup(subparam);
 
946
            memset(&lst[2*(nr+1)],0,2*sizeof(char*));
 
947
            nr++;
 
948
          }
 
949
          break;
 
950
        }
 
951
    }
 
952
 
 
953
  free(subparam);
 
954
  free(subopt);
 
955
  if(dst)
 
956
    VAL(dst) = lst;
 
957
 
 
958
  return 1;
 
959
}
 
960
 
 
961
m_option_type_t m_option_type_subconfig = {
 
962
  "Subconfig",
 
963
  "The syntax is -option opt1=foo:flag:opt2=blah",
 
964
  sizeof(int),
 
965
  M_OPT_TYPE_HAS_CHILD,
 
966
  parse_subconf,
 
967
  NULL,
 
968
  NULL,
 
969
  NULL,
 
970
  NULL,
 
971
  NULL
 
972
};
 
973
 
 
974
#include "libmpcodecs/img_format.h"
 
975
 
 
976
/* FIXME: snyc with img_format.h */
 
977
static struct {
 
978
  char* name;
 
979
  unsigned int fmt;
 
980
} mp_imgfmt_list[] = {
 
981
  {"444p", IMGFMT_444P},
 
982
  {"422p", IMGFMT_422P},
 
983
  {"411p", IMGFMT_411P},
 
984
  {"yuy2", IMGFMT_YUY2},
 
985
  {"uyvy", IMGFMT_UYVY},
 
986
  {"yvu9", IMGFMT_YVU9},
 
987
  {"if09", IMGFMT_IF09},
 
988
  {"yv12", IMGFMT_YV12},
 
989
  {"i420", IMGFMT_I420},
 
990
  {"iyuv", IMGFMT_IYUV},
 
991
  {"clpl", IMGFMT_CLPL},
 
992
  {"hm12", IMGFMT_HM12},
 
993
  {"y800", IMGFMT_Y800},
 
994
  {"y8", IMGFMT_Y8},
 
995
  {"nv12", IMGFMT_NV12},
 
996
  {"nv21", IMGFMT_NV21},
 
997
  {"bgr24", IMGFMT_BGR24},
 
998
  {"bgr32", IMGFMT_BGR32},
 
999
  {"bgr16", IMGFMT_BGR16},
 
1000
  {"bgr15", IMGFMT_BGR15},
 
1001
  {"bgr8", IMGFMT_BGR8},
 
1002
  {"bgr4", IMGFMT_BGR4},
 
1003
  {"bg4b", IMGFMT_BG4B},
 
1004
  {"bgr1", IMGFMT_BGR1},
 
1005
  {"rgb24", IMGFMT_RGB24},
 
1006
  {"rgb32", IMGFMT_RGB32},
 
1007
  {"rgb16", IMGFMT_RGB16},
 
1008
  {"rgb15", IMGFMT_RGB15},
 
1009
  {"rgb8", IMGFMT_RGB8},
 
1010
  {"rgb4", IMGFMT_RGB4},
 
1011
  {"rg4b", IMGFMT_RG4B},
 
1012
  {"rgb1", IMGFMT_RGB1},
 
1013
  {"rgba", IMGFMT_RGBA},
 
1014
  {"argb", IMGFMT_ARGB},
 
1015
  {"bgra", IMGFMT_BGRA},
 
1016
  {"abgr", IMGFMT_ABGR},
 
1017
  { NULL, 0 }
 
1018
};
 
1019
 
 
1020
static int parse_imgfmt(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
1021
  uint32_t fmt = 0;
 
1022
  int i;
 
1023
 
 
1024
  if (param == NULL || strlen(param) == 0)
 
1025
    return M_OPT_MISSING_PARAM;
 
1026
 
 
1027
  if(!strcmp(param,"help")) {
 
1028
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
 
1029
    for(i = 0 ; mp_imgfmt_list[i].name ; i++)
 
1030
      mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s",mp_imgfmt_list[i].name);
 
1031
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
 
1032
    return M_OPT_EXIT - 1;
 
1033
  }
 
1034
  
 
1035
  if (sscanf(param, "0x%x", &fmt) != 1)
 
1036
  {
 
1037
  for(i = 0 ; mp_imgfmt_list[i].name ; i++) {
 
1038
    if(!strcasecmp(param,mp_imgfmt_list[i].name)) {
 
1039
      fmt=mp_imgfmt_list[i].fmt;
 
1040
      break;
 
1041
    }
 
1042
  }
 
1043
  if(!mp_imgfmt_list[i].name) {
 
1044
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: unknown format name: '%s'\n",name,param);
 
1045
    return M_OPT_INVALID;
 
1046
  }
 
1047
  }
 
1048
 
 
1049
  if(dst)
 
1050
    *((uint32_t*)dst) = fmt;
 
1051
 
 
1052
  return 1;
 
1053
}
 
1054
 
 
1055
m_option_type_t m_option_type_imgfmt = {
 
1056
  "Image format",
 
1057
  "Please report any missing colorspaces.",
 
1058
  sizeof(uint32_t),
 
1059
  0,
 
1060
  parse_imgfmt,
 
1061
  NULL,
 
1062
  copy_opt,
 
1063
  copy_opt,
 
1064
  NULL,
 
1065
  NULL
 
1066
};
 
1067
 
 
1068
#include "libaf/af_format.h"
 
1069
 
 
1070
/* FIXME: snyc with af_format.h */
 
1071
static struct {
 
1072
  char* name;
 
1073
  unsigned int fmt;
 
1074
} mp_afmt_list[] = {
 
1075
  // SPECIAL
 
1076
  {"mulaw", AF_FORMAT_MU_LAW},
 
1077
  {"alaw", AF_FORMAT_A_LAW},
 
1078
  {"mpeg2", AF_FORMAT_MPEG2},
 
1079
  {"ac3", AF_FORMAT_AC3},
 
1080
  {"imaadpcm", AF_FORMAT_IMA_ADPCM},
 
1081
  // ORIDNARY
 
1082
  {"u8", AF_FORMAT_U8},
 
1083
  {"s8", AF_FORMAT_S8},
 
1084
  {"u16le", AF_FORMAT_U16_LE},
 
1085
  {"u16be", AF_FORMAT_U16_BE},
 
1086
  {"u16ne", AF_FORMAT_U16_NE},
 
1087
  {"s16le", AF_FORMAT_S16_LE},
 
1088
  {"s16be", AF_FORMAT_S16_BE},
 
1089
  {"s16ne", AF_FORMAT_S16_NE},
 
1090
  {"u24le", AF_FORMAT_U24_LE},
 
1091
  {"u24be", AF_FORMAT_U24_BE},
 
1092
  {"u24ne", AF_FORMAT_U24_NE},
 
1093
  {"s24le", AF_FORMAT_S24_LE},
 
1094
  {"s24be", AF_FORMAT_S24_BE},
 
1095
  {"s24ne", AF_FORMAT_S24_NE},
 
1096
  {"u32le", AF_FORMAT_U32_LE},
 
1097
  {"u32be", AF_FORMAT_U32_BE},
 
1098
  {"u32ne", AF_FORMAT_U32_NE},
 
1099
  {"s32le", AF_FORMAT_S32_LE},
 
1100
  {"s32be", AF_FORMAT_S32_BE},
 
1101
  {"s32ne", AF_FORMAT_S32_NE},
 
1102
  {"floatle", AF_FORMAT_FLOAT_LE},
 
1103
  {"floatbe", AF_FORMAT_FLOAT_BE},
 
1104
  {"floatne", AF_FORMAT_FLOAT_NE},
 
1105
  { NULL, 0 }
 
1106
};
 
1107
 
 
1108
static int parse_afmt(m_option_t* opt,char *name, char *param, void* dst, int src) {
 
1109
  uint32_t fmt = 0;
 
1110
  int i;
 
1111
 
 
1112
  if (param == NULL || strlen(param) == 0)
 
1113
    return M_OPT_MISSING_PARAM;
 
1114
 
 
1115
  if(!strcmp(param,"help")) {
 
1116
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available formats:");
 
1117
    for(i = 0 ; mp_afmt_list[i].name ; i++)
 
1118
      mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %s",mp_afmt_list[i].name);
 
1119
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
 
1120
    return M_OPT_EXIT - 1;
 
1121
  }
 
1122
  
 
1123
  if (sscanf(param, "0x%x", &fmt) != 1)
 
1124
  {
 
1125
  for(i = 0 ; mp_afmt_list[i].name ; i++) {
 
1126
    if(!strcasecmp(param,mp_afmt_list[i].name)) {
 
1127
      fmt=mp_afmt_list[i].fmt;
 
1128
      break;
 
1129
    }
 
1130
  }
 
1131
  if(!mp_afmt_list[i].name) {
 
1132
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: unknown format name: '%s'\n",name,param);
 
1133
    return M_OPT_INVALID;
 
1134
  }
 
1135
  }
 
1136
 
 
1137
  if(dst)
 
1138
    *((uint32_t*)dst) = fmt;
 
1139
 
 
1140
  return 1;
 
1141
}
 
1142
 
 
1143
m_option_type_t m_option_type_afmt = {
 
1144
  "Audio format",
 
1145
  "Please report any missing formats.",
 
1146
  sizeof(uint32_t),
 
1147
  0,
 
1148
  parse_afmt,
 
1149
  NULL,
 
1150
  copy_opt,
 
1151
  copy_opt,
 
1152
  NULL,
 
1153
  NULL
 
1154
};
 
1155
 
 
1156
 
 
1157
//// Objects (i.e. filters, etc) settings
 
1158
 
 
1159
#include "m_struct.h"
 
1160
 
 
1161
#undef VAL
 
1162
#define VAL(x) (*(m_obj_settings_t**)(x))
 
1163
 
 
1164
static int find_obj_desc(char* name,m_obj_list_t* l,m_struct_t** ret) {
 
1165
  int i;
 
1166
  char* n;
 
1167
 
 
1168
  for(i = 0 ; l->list[i] ; i++) {
 
1169
    n = M_ST_MB(char*,l->list[i],l->name_off);
 
1170
    if(!strcmp(n,name)) {
 
1171
      *ret = M_ST_MB(m_struct_t*,l->list[i],l->desc_off);
 
1172
      return 1;
 
1173
    }
 
1174
  }
 
1175
  return 0;
 
1176
}
 
1177
 
 
1178
static int get_obj_param(char* opt_name,char* obj_name, m_struct_t* desc,
 
1179
                         char* str,int* nold,int oldmax,char** dst) {
 
1180
  char* eq,param;
 
1181
  m_option_t* opt;
 
1182
  int r;
 
1183
 
 
1184
  eq = strchr(str,'=');
 
1185
  if(eq && eq == str)
 
1186
    eq = NULL;
 
1187
 
 
1188
  if(eq) {
 
1189
    char* p = eq + 1;
 
1190
    if(p[0] == '\0') p = NULL;
 
1191
    eq[0] = '\0';
 
1192
    opt = m_option_list_find(desc->fields,str);
 
1193
    if(!opt) {
 
1194
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s doesn't have a %s parameter.\n",opt_name,obj_name,str);
 
1195
      return M_OPT_UNKNOWN;
 
1196
    }
 
1197
    r = m_option_parse(opt,str,p,NULL,M_CONFIG_FILE);
 
1198
    if(r < 0) {
 
1199
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while parsing %s parameter %s (%s)\n",opt_name,obj_name,str,p);
 
1200
      eq[0] = '=';
 
1201
      return r;
 
1202
    }
 
1203
    if(dst) {
 
1204
      dst[0] = strdup(str);
 
1205
      dst[1] = p ? strdup(p) : NULL;
 
1206
    }
 
1207
    eq[0] = '=';
 
1208
  } else {
 
1209
    if((*nold) >= oldmax) {
 
1210
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s has only %d params, so you can't give more than %d unnamed params.\n",
 
1211
             opt_name,obj_name,oldmax,oldmax);
 
1212
      return M_OPT_OUT_OF_RANGE;
 
1213
    }
 
1214
    opt = &desc->fields[(*nold)];
 
1215
    r = m_option_parse(opt,opt->name,str,NULL,M_CONFIG_FILE);
 
1216
    if(r < 0) {
 
1217
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while parsing %s parameter %s (%s)\n",opt_name,obj_name,opt->name,str);
 
1218
      return r;
 
1219
    }
 
1220
    if(dst) {
 
1221
      dst[0] = strdup(opt->name);
 
1222
      dst[1] = strdup(str);
 
1223
    }
 
1224
    (*nold)++;
 
1225
  }
 
1226
  return 1;
 
1227
}
 
1228
 
 
1229
static int get_obj_params(char* opt_name, char* name,char* params,
 
1230
                          m_struct_t* desc,char separator, char*** _ret) {
 
1231
  int n = 0,nold = 0, nopts,r;
 
1232
  char* ptr,*last_ptr = params,*eq;
 
1233
  char** ret;
 
1234
 
 
1235
  if(!strcmp(params,"help")) { // Help
 
1236
    char min[50],max[50];
 
1237
    if(!desc->fields) {
 
1238
      printf("%s doesn't have any options.\n\n",name);
 
1239
      return M_OPT_EXIT - 1;
 
1240
    }
 
1241
    printf("\n Name                 Type            Min        Max\n\n");
 
1242
    for(n = 0 ; desc->fields[n].name ; n++) {
 
1243
      m_option_t* opt = &desc->fields[n];
 
1244
      if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue;
 
1245
      if(opt->flags & M_OPT_MIN)
 
1246
        sprintf(min,"%-8.0f",opt->min);
 
1247
      else
 
1248
        strcpy(min,"No");
 
1249
      if(opt->flags & M_OPT_MAX)
 
1250
        sprintf(max,"%-8.0f",opt->max);
 
1251
      else
 
1252
        strcpy(max,"No");
 
1253
      printf(" %-20.20s %-15.15s %-10.10s %-10.10s\n",
 
1254
             opt->name,
 
1255
             opt->type->name,
 
1256
             min,
 
1257
             max);
 
1258
    }
 
1259
    printf("\n");
 
1260
    return M_OPT_EXIT - 1;
 
1261
  }
 
1262
 
 
1263
  for(nopts = 0 ; desc->fields[nopts].name ; nopts++)
 
1264
    /* NOP */;
 
1265
 
 
1266
  // TODO : Check that each opt can be parsed
 
1267
  r = 1;
 
1268
  while(last_ptr && last_ptr[0] != '\0') {
 
1269
    ptr = strchr(last_ptr,separator);
 
1270
    if(!ptr) {
 
1271
      r = get_obj_param(opt_name,name,desc,last_ptr,&nold,nopts,NULL);
 
1272
      n++;
 
1273
      break;
 
1274
    }
 
1275
    if(ptr == last_ptr) { // Empty field, count it and go on
 
1276
      nold++;
 
1277
      last_ptr = ptr+1;
 
1278
      continue;
 
1279
    }
 
1280
    ptr[0] = '\0';
 
1281
    r = get_obj_param(opt_name,name,desc,last_ptr,&nold,nopts,NULL);
 
1282
    ptr[0] = separator;
 
1283
    if(r < 0) break;
 
1284
    n++;
 
1285
    last_ptr = ptr+1;
 
1286
  }
 
1287
  if(r < 0) return r;
 
1288
  if (!last_ptr[0]) // count an empty field at the end, too
 
1289
    nold++;
 
1290
  if (nold > nopts) {
 
1291
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Too many options for %s\n", name);
 
1292
    return M_OPT_OUT_OF_RANGE;
 
1293
  }
 
1294
  if(!_ret) // Just test
 
1295
    return 1;
 
1296
  if (n == 0) // No options or only empty options
 
1297
    return 1;
 
1298
 
 
1299
  ret = malloc((n+2)*2*sizeof(char*));
 
1300
  n = nold = 0;
 
1301
  last_ptr = params;
 
1302
  
 
1303
  while(last_ptr && last_ptr[0] != '\0') {
 
1304
    ptr = strchr(last_ptr,separator);
 
1305
    if(!ptr) {
 
1306
      get_obj_param(opt_name,name,desc,last_ptr,&nold,nopts,&ret[n*2]);
 
1307
      n++;
 
1308
      break;
 
1309
    }
 
1310
    if(ptr == last_ptr) { // Empty field, count it and go on
 
1311
      last_ptr = ptr+1;
 
1312
      nold++;
 
1313
      continue;
 
1314
    }
 
1315
    ptr[0] = '\0';
 
1316
    get_obj_param(opt_name,name,desc,last_ptr,&nold,nopts,&ret[n*2]);
 
1317
    n++;
 
1318
    last_ptr = ptr+1;
 
1319
  }
 
1320
  ret[n*2] = ret[n*2+1] = NULL;  
 
1321
  *_ret = ret;
 
1322
  
 
1323
  return 1;
 
1324
}
 
1325
 
 
1326
static int parse_obj_params(m_option_t* opt,char *name,
 
1327
                            char *param, void* dst, int src) {
 
1328
  char** opts;
 
1329
  int r;
 
1330
  m_obj_params_t* p = opt->priv;
 
1331
  m_struct_t* desc = p->desc;
 
1332
  char* cpy = strdup(param);
 
1333
  
 
1334
  // We need the object desc
 
1335
  if(!p)
 
1336
    return M_OPT_INVALID;
 
1337
  
 
1338
  r = get_obj_params(name,desc->name,cpy,desc,p->separator,&opts);
 
1339
  free(cpy);
 
1340
  if(r < 0)
 
1341
    return r;
 
1342
  if(!dst)
 
1343
    return 1;
 
1344
  if (!opts) // no arguments given
 
1345
    return 1;
 
1346
 
 
1347
  for(r = 0 ; opts[r] ; r += 2)
 
1348
    m_struct_set(desc,dst,opts[r],opts[r+1]);
 
1349
 
 
1350
  return 1;     
 
1351
}
 
1352
 
 
1353
 
 
1354
m_option_type_t m_option_type_obj_params = {
 
1355
  "Object params",
 
1356
  "",
 
1357
  0,
 
1358
  0,
 
1359
  parse_obj_params,
 
1360
  NULL,
 
1361
  NULL,
 
1362
  NULL,
 
1363
  NULL,
 
1364
  NULL
 
1365
};
 
1366
 
 
1367
/// Some predefined types as a definition would be quite lengthy
 
1368
 
 
1369
/// Span arguments
 
1370
static m_span_t m_span_params_dflts = { -1, -1 };
 
1371
static m_option_t m_span_params_fields[] = {
 
1372
  {"start", M_ST_OFF(m_span_t,start), CONF_TYPE_INT, M_OPT_MIN, 1 ,0, NULL},
 
1373
  {"end", M_ST_OFF(m_span_t,end), CONF_TYPE_INT, M_OPT_MIN , 1 ,0, NULL},
 
1374
  { NULL, NULL, 0, 0, 0, 0,  NULL }
 
1375
};
 
1376
static struct m_struct_st m_span_opts = {
 
1377
  "m_span",
 
1378
  sizeof(m_span_t),
 
1379
  &m_span_params_dflts,
 
1380
  m_span_params_fields
 
1381
};
 
1382
m_obj_params_t m_span_params_def = {
 
1383
  &m_span_opts,
 
1384
  '-'
 
1385
};
 
1386
 
 
1387
static int parse_obj_settings(char* opt,char* str,m_obj_list_t* list,
 
1388
                              m_obj_settings_t **_ret, int ret_n) {
 
1389
  int r;
 
1390
  char *param,**plist = NULL;
 
1391
  m_struct_t* desc;
 
1392
  m_obj_settings_t *ret = _ret ? *_ret : NULL;
 
1393
  
 
1394
 
 
1395
  // Now check that the object exists
 
1396
  param = strchr(str,'=');
 
1397
  if(param) {
 
1398
    param[0] = '\0';
 
1399
    param++;
 
1400
    if(strlen(param) <= 0)
 
1401
      param = NULL;
 
1402
  }
 
1403
 
 
1404
 
 
1405
  if(!find_obj_desc(str,list,&desc)) {
 
1406
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: %s doesn't exist.\n",opt,str);
 
1407
    return M_OPT_INVALID;
 
1408
  }
 
1409
 
 
1410
  if(param) {
 
1411
    if(!desc && _ret) {
 
1412
      plist = calloc(4,sizeof(char*));
 
1413
      plist[0] = strdup("_oldargs_");
 
1414
      plist[1] = strdup(param);
 
1415
    } else if(desc) {
 
1416
      r = get_obj_params(opt,str,param,desc,':',_ret ? &plist : NULL);
 
1417
      if(r < 0)
 
1418
        return r;
 
1419
    }
 
1420
  }
 
1421
  if(!_ret)
 
1422
    return 1;
 
1423
 
 
1424
  ret = realloc(ret,(ret_n+2)*sizeof(m_obj_settings_t));
 
1425
  memset(&ret[ret_n],0,2*sizeof(m_obj_settings_t));
 
1426
  ret[ret_n].name = strdup(str);
 
1427
  ret[ret_n].attribs = plist;
 
1428
 
 
1429
  *_ret = ret;
 
1430
  return 1;
 
1431
}
 
1432
 
 
1433
static void free_obj_settings_list(void* dst);
 
1434
 
 
1435
static int obj_settings_list_del(char *opt_name,char *param,void* dst, int src) {
 
1436
  char** str_list = NULL;
 
1437
  int r,i,idx_max = 0;
 
1438
  char* rem_id = "_removed_marker_";
 
1439
  m_option_t list_opt = {opt_name , NULL, CONF_TYPE_STRING_LIST,
 
1440
                           0, 0, 0, NULL };
 
1441
  m_obj_settings_t* obj_list = dst ? VAL(dst) : NULL;
 
1442
 
 
1443
  if(dst && !obj_list) {
 
1444
    mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: the list is empty.\n",opt_name);
 
1445
    return 1;
 
1446
  } else if(obj_list) {
 
1447
    for(idx_max = 0 ; obj_list[idx_max].name != NULL ; idx_max++)
 
1448
      /* NOP */;
 
1449
  }
 
1450
 
 
1451
  r = m_option_parse(&list_opt,opt_name,param,&str_list,src);
 
1452
  if(r < 0 || !str_list)
 
1453
    return r;
 
1454
 
 
1455
  for(r = 0 ; str_list[r] ; r++) {
 
1456
    int id;
 
1457
    char* endptr;
 
1458
    id = strtol(str_list[r],&endptr,0);
 
1459
    if(endptr == str_list[r]) {
 
1460
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid parameter. We need a list of integers which are the indices of the elements to remove.\n",opt_name);
 
1461
      m_option_free(&list_opt,&str_list);
 
1462
      return M_OPT_INVALID;
 
1463
    }
 
1464
    if(!obj_list) continue;
 
1465
    if(id >= idx_max || id < -idx_max) {
 
1466
      mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: Index %d is out of range.\n",opt_name,id);
 
1467
      continue;
 
1468
    }
 
1469
    if(id < 0)
 
1470
      id = idx_max + id;
 
1471
    free(obj_list[id].name);
 
1472
    free_str_list(&(obj_list[id].attribs));
 
1473
    obj_list[id].name = rem_id;
 
1474
  }
 
1475
 
 
1476
  if(!dst) {
 
1477
    m_option_free(&list_opt,&str_list);
 
1478
    return 1;
 
1479
  }
 
1480
 
 
1481
  for(i = 0 ; obj_list[i].name ; i++) {
 
1482
    while(obj_list[i].name == rem_id) {
 
1483
      memmove(&obj_list[i],&obj_list[i+1],sizeof(m_obj_settings_t)*(idx_max - i));
 
1484
      idx_max--;
 
1485
    }
 
1486
  }
 
1487
  obj_list = realloc(obj_list,sizeof(m_obj_settings_t)*(idx_max+1));
 
1488
  VAL(dst) = obj_list;
 
1489
 
 
1490
  return 1;
 
1491
}
 
1492
 
 
1493
static int parse_obj_settings_list(m_option_t* opt,char *name,
 
1494
                                   char *param, void* dst, int src) {
 
1495
  int n = 0,r,len = strlen(opt->name);
 
1496
  char *str;
 
1497
  char *ptr, *last_ptr;
 
1498
  m_obj_settings_t *res = NULL,*queue = NULL,*head = NULL;
 
1499
  int op = OP_NONE;
 
1500
 
 
1501
  // We need the objects list
 
1502
  if(!opt->priv)
 
1503
    return M_OPT_INVALID;
 
1504
 
 
1505
  if(opt->name[len-1] == '*' && ((int)strlen(name) > len - 1)) {
 
1506
    char* n = &name[len-1];
 
1507
    if(strcasecmp(n,"-add") == 0)
 
1508
      op = OP_ADD;
 
1509
    else if(strcasecmp(n,"-pre") == 0)
 
1510
      op = OP_PRE;
 
1511
    else if(strcasecmp(n,"-del") == 0)
 
1512
      op = OP_DEL;
 
1513
    else if(strcasecmp(n,"-clr") == 0)
 
1514
      op = OP_CLR;
 
1515
    else {
 
1516
      char prefix[len];
 
1517
      strncpy(prefix,opt->name,len-1);
 
1518
      prefix[len-1] = '\0';
 
1519
      mp_msg(MSGT_VFILTER,MSGL_ERR, "Option %s: unknown postfix %s\n"
 
1520
             "Supported postfixes are:\n"
 
1521
             "  %s-add\n"
 
1522
             " Append the given list to the current list\n\n"
 
1523
             "  %s-pre\n"
 
1524
             " Prepend the given list to the current list\n\n"
 
1525
             "  %s-del x,y,...\n"
 
1526
             " Remove the given elements. Take the list element index (starting from 0).\n"
 
1527
             " Negative index can be used (i.e. -1 is the last element)\n\n"
 
1528
             "  %s-clr\n"
 
1529
             " Clear the current list.\n",name,n,prefix,prefix,prefix,prefix);
 
1530
      
 
1531
      return M_OPT_UNKNOWN;
 
1532
    }
 
1533
  }
 
1534
 
 
1535
  // Clear the list ??
 
1536
  if(op == OP_CLR) {
 
1537
    if(dst)
 
1538
      free_obj_settings_list(dst);
 
1539
    return 0;
 
1540
  }
 
1541
 
 
1542
  if (param == NULL || strlen(param) == 0)
 
1543
    return M_OPT_MISSING_PARAM;
 
1544
 
 
1545
  switch(op) {
 
1546
  case OP_ADD:
 
1547
    if(dst) head = VAL(dst);
 
1548
    break;
 
1549
  case OP_PRE:
 
1550
    if(dst) queue = VAL(dst);
 
1551
     break;
 
1552
  case OP_DEL:
 
1553
    return obj_settings_list_del(name,param,dst,src);
 
1554
  case OP_NONE:
 
1555
    if(dst && VAL(dst))
 
1556
      free_obj_settings_list(dst);
 
1557
    break;
 
1558
  default:
 
1559
    mp_msg(MSGT_VFILTER,MSGL_ERR, "Option %s: FIXME\n",name);
 
1560
    return M_OPT_UNKNOWN;
 
1561
  }
 
1562
 
 
1563
  if(!strcmp(param,"help")) {
 
1564
    m_obj_list_t* ol = opt->priv;
 
1565
    mp_msg(MSGT_VFILTER,MSGL_INFO,"Available video filters:\n");
 
1566
    if (identify)
 
1567
      mp_msg(MSGT_GLOBAL, MSGL_INFO, "ID_VIDEO_FILTERS\n");
 
1568
    for(n = 0 ; ol->list[n] ; n++)
 
1569
      mp_msg(MSGT_VFILTER,MSGL_INFO,"  %-15s: %s\n",
 
1570
             M_ST_MB(char*,ol->list[n],ol->name_off),
 
1571
             M_ST_MB(char*,ol->list[n],ol->info_off));
 
1572
    return M_OPT_EXIT - 1;
 
1573
  }
 
1574
  ptr = str = strdup(param);
 
1575
 
 
1576
  while(ptr[0] != '\0') {
 
1577
    last_ptr = ptr;
 
1578
    ptr = strchr(ptr,LIST_SEPARATOR);
 
1579
    if(!ptr) {
 
1580
      r = parse_obj_settings(name,last_ptr,opt->priv,dst ? &res : NULL,n);
 
1581
      if(r < 0) {
 
1582
        free(str);
 
1583
        return r;
 
1584
      }
 
1585
      n++;
 
1586
      break;
 
1587
    }
 
1588
    ptr[0] = '\0';
 
1589
    r = parse_obj_settings(name,last_ptr,opt->priv,dst ? &res : NULL,n);
 
1590
    if(r < 0) {
 
1591
      free(str);
 
1592
      return r;
 
1593
    }
 
1594
    ptr++;
 
1595
    n++;
 
1596
  }
 
1597
  free(str);
 
1598
  if(n == 0)
 
1599
    return M_OPT_INVALID;
 
1600
 
 
1601
  if( ((opt->flags & M_OPT_MIN) && (n < opt->min)) || 
 
1602
      ((opt->flags & M_OPT_MAX) && (n > opt->max)) )
 
1603
    return M_OPT_OUT_OF_RANGE;
 
1604
  
 
1605
  if(dst) {
 
1606
    if(queue) {
 
1607
      int qsize;
 
1608
      for(qsize = 0 ; queue[qsize].name ; qsize++)
 
1609
        /* NOP */;
 
1610
      res = realloc(res,(qsize+n+1)*sizeof(m_obj_settings_t));
 
1611
      memcpy(&res[n],queue,(qsize+1)*sizeof(m_obj_settings_t));
 
1612
      n += qsize;
 
1613
      free(queue);
 
1614
    }
 
1615
    if(head) {
 
1616
      int hsize;
 
1617
      for(hsize = 0 ; head[hsize].name ; hsize++)
 
1618
        /* NOP */;
 
1619
      head = realloc(head,(hsize+n+1)*sizeof(m_obj_settings_t));
 
1620
      memcpy(&head[hsize],res,(n+1)*sizeof(m_obj_settings_t));
 
1621
      free(res);
 
1622
      res = head;
 
1623
    }      
 
1624
    VAL(dst) = res;
 
1625
  }
 
1626
  return 1;
 
1627
}
 
1628
 
 
1629
static void free_obj_settings_list(void* dst) {
 
1630
  int n;
 
1631
  m_obj_settings_t *d;
 
1632
 
 
1633
  if(!dst || !VAL(dst)) return;
 
1634
 
 
1635
  d = VAL(dst);
 
1636
#ifndef NO_FREE
 
1637
  for(n = 0 ; d[n].name ; n++) {
 
1638
    free(d[n].name);
 
1639
    free_str_list(&(d[n].attribs));
 
1640
  }
 
1641
  free(d);
 
1642
#endif
 
1643
  VAL(dst) = NULL;
 
1644
}
 
1645
 
 
1646
static void copy_obj_settings_list(m_option_t* opt,void* dst, void* src) {
 
1647
  m_obj_settings_t *d,*s;
 
1648
  int n;
 
1649
 
 
1650
  if(!(dst && src))
 
1651
    return;
 
1652
 
 
1653
  s = VAL(src);
 
1654
 
 
1655
  if(VAL(dst))
 
1656
    free_obj_settings_list(dst);
 
1657
  if(!s) return;
 
1658
    
 
1659
    
 
1660
  
 
1661
  for(n = 0 ; s[n].name ; n++)
 
1662
    /* NOP */;
 
1663
  d = malloc((n+1)*sizeof(m_obj_settings_t));
 
1664
  for(n = 0 ; s[n].name ; n++) {
 
1665
    d[n].name = strdup(s[n].name);
 
1666
    d[n].attribs = NULL;
 
1667
    copy_str_list(NULL,&(d[n].attribs),&(s[n].attribs));
 
1668
  }
 
1669
  d[n].name = NULL;
 
1670
  d[n].attribs = NULL;
 
1671
  VAL(dst) = d;
 
1672
}
 
1673
 
 
1674
m_option_type_t m_option_type_obj_settings_list = {
 
1675
  "Object settings list",
 
1676
  "",
 
1677
  sizeof(m_obj_settings_t*),
 
1678
  M_OPT_TYPE_DYNAMIC|M_OPT_TYPE_ALLOW_WILDCARD,
 
1679
  parse_obj_settings_list,
 
1680
  NULL,
 
1681
  copy_obj_settings_list,
 
1682
  copy_obj_settings_list,
 
1683
  copy_obj_settings_list,
 
1684
  free_obj_settings_list,
 
1685
};
 
1686
 
 
1687
 
 
1688
 
 
1689
static int parse_obj_presets(m_option_t* opt,char *name,
 
1690
                            char *param, void* dst, int src) {
 
1691
  m_obj_presets_t* obj_p = (m_obj_presets_t*)opt->priv;
 
1692
  m_struct_t *in_desc,*out_desc;
 
1693
  int s,i;
 
1694
  unsigned char* pre = obj_p->presets;
 
1695
  char* pre_name = NULL;
 
1696
 
 
1697
  if(!obj_p) {
 
1698
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Presets need a pointer to a m_obj_presets_t in the priv field.\n",name);
 
1699
    return M_OPT_PARSER_ERR;
 
1700
  }
 
1701
 
 
1702
  if(!param)
 
1703
    return M_OPT_MISSING_PARAM;
 
1704
 
 
1705
  in_desc = obj_p->in_desc;
 
1706
  out_desc = obj_p->out_desc ? obj_p->out_desc : obj_p->in_desc;
 
1707
  s = in_desc->size;
 
1708
 
 
1709
  if(!strcmp(param,"help")) {
 
1710
    mp_msg(MSGT_CFGPARSER, MSGL_INFO, "Available presets for %s->%s:",out_desc->name,name);
 
1711
    for(pre = obj_p->presets;(pre_name = M_ST_MB(char*,pre,obj_p->name_off)) ; 
 
1712
        pre +=  s) 
 
1713
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s",pre_name);
 
1714
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
 
1715
    return M_OPT_EXIT - 1;
 
1716
  }
 
1717
 
 
1718
  for(pre_name = M_ST_MB(char*,pre,obj_p->name_off) ; pre_name ;
 
1719
      pre +=  s, pre_name = M_ST_MB(char*,pre,obj_p->name_off)) {
 
1720
    if(!strcmp(pre_name,param)) break;
 
1721
  }
 
1722
  if(!pre_name) {
 
1723
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: There is no preset named %s\n"
 
1724
           "Available presets are:",name,param);
 
1725
    for(pre = obj_p->presets;(pre_name = M_ST_MB(char*,pre,obj_p->name_off)) ; 
 
1726
        pre +=  s) 
 
1727
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, " %s",pre_name);
 
1728
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "\n");
 
1729
    return M_OPT_INVALID;
 
1730
  }
 
1731
 
 
1732
  if(!dst) return 1;
 
1733
  
 
1734
  for(i = 0 ; in_desc->fields[i].name ; i++) {
 
1735
    m_option_t* out_opt = m_option_list_find(out_desc->fields,
 
1736
                                             in_desc->fields[i].name);
 
1737
    if(!out_opt) {
 
1738
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Unable to find the target option for field %s.\nPlease report this to the developers.\n",name,in_desc->fields[i].name);
 
1739
      return M_OPT_PARSER_ERR;
 
1740
    }
 
1741
    m_option_copy(out_opt,M_ST_MB_P(dst,out_opt->p),M_ST_MB_P(pre,in_desc->fields[i].p));
 
1742
  }
 
1743
  return 1;
 
1744
}
 
1745
 
 
1746
 
 
1747
m_option_type_t m_option_type_obj_presets = {
 
1748
  "Object presets",
 
1749
  "",
 
1750
  0,
 
1751
  0,
 
1752
  parse_obj_presets,
 
1753
  NULL,
 
1754
  NULL,
 
1755
  NULL,
 
1756
  NULL,
 
1757
  NULL
 
1758
};
 
1759
 
 
1760
static int parse_custom_url(m_option_t* opt,char *name,
 
1761
                            char *url, void* dst, int src) {
 
1762
  int pos1, pos2, r, v6addr = 0;
 
1763
  char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL;
 
1764
  m_struct_t* desc = opt->priv;
 
1765
  
 
1766
  if(!desc) {
 
1767
    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Custom URL needs a pointer to a m_struct_t in the priv field.\n",name);
 
1768
    return M_OPT_PARSER_ERR;
 
1769
  }
 
1770
 
 
1771
  // extract the protocol
 
1772
  ptr1 = strstr(url, "://");
 
1773
  if( ptr1==NULL ) {
 
1774
    // Filename only
 
1775
    if(m_option_list_find(desc->fields,"filename")) {
 
1776
      m_struct_set(desc,dst,"filename",url);
 
1777
      return 1;
 
1778
    }
 
1779
    mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Option %s: URL doesn't have a valid protocol!\n",name);
 
1780
    return M_OPT_INVALID;
 
1781
  }
 
1782
  if(m_option_list_find(desc->fields,"string")) {
 
1783
    if(strlen(ptr1)>3) {
 
1784
      m_struct_set(desc,dst,"string",ptr1+3);
 
1785
      return 1;
 
1786
    }
 
1787
  }
 
1788
  pos1 = ptr1-url;
 
1789
  if(dst && m_option_list_find(desc->fields,"protocol")) {
 
1790
    ptr1[0] = '\0';
 
1791
    r = m_struct_set(desc,dst,"protocol",url);
 
1792
    ptr1[0] = ':';
 
1793
    if(r < 0) {
 
1794
      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting protocol.\n",name);
 
1795
      return r;
 
1796
    }
 
1797
  }
 
1798
 
 
1799
  // jump the "://"
 
1800
  ptr1 += 3;
 
1801
  pos1 += 3;
 
1802
 
 
1803
  // check if a username:password is given
 
1804
  ptr2 = strstr(ptr1, "@");
 
1805
  ptr3 = strstr(ptr1, "/");
 
1806
  if( ptr3!=NULL && ptr3<ptr2 ) {
 
1807
    // it isn't really a username but rather a part of the path
 
1808
    ptr2 = NULL;
 
1809
  }
 
1810
  if( ptr2!=NULL ) {
 
1811
    
 
1812
    // We got something, at least a username...
 
1813
    int len = ptr2-ptr1;
 
1814
    if(!m_option_list_find(desc->fields,"username")) {
 
1815
      mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a username part.\n",name);
 
1816
      // skip
 
1817
    } else {
 
1818
      ptr3 = strstr(ptr1, ":");
 
1819
      if( ptr3!=NULL && ptr3<ptr2 ) {
 
1820
        // We also have a password
 
1821
        int len2 = ptr2-ptr3-1;
 
1822
        if(!m_option_list_find(desc->fields,"password")) {
 
1823
          mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a password part.\n",name);
 
1824
          // skip
 
1825
        } else { // Username and password   
 
1826
          if(dst) {
 
1827
            ptr3[0] = '\0';
 
1828
            r = m_struct_set(desc,dst,"username",ptr1);
 
1829
            ptr3[0] = ':';
 
1830
            if(r < 0) {
 
1831
              mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting username.\n",name);
 
1832
              return r;
 
1833
            }
 
1834
            ptr2[0] = '\0';
 
1835
            r = m_struct_set(desc,dst,"password",ptr3+1);
 
1836
            ptr2[0] = '@';
 
1837
            if(r < 0) {
 
1838
              mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting password.\n",name);
 
1839
              return r;
 
1840
            }
 
1841
          }
 
1842
        }
 
1843
      } else { // User name only
 
1844
        ptr2[0] = '\0';
 
1845
        r = m_struct_set(desc,dst,"username",ptr1);
 
1846
        ptr2[0] = '@';
 
1847
        if(r < 0) {
 
1848
          mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting username.\n",name);
 
1849
          return r;
 
1850
        }
 
1851
      }
 
1852
    }
 
1853
    ptr1 = ptr2+1;
 
1854
    pos1 = ptr1-url;
 
1855
  }
 
1856
 
 
1857
  // before looking for a port number check if we have an IPv6 type numeric address
 
1858
  // in an IPv6 URL the numeric address should be inside square braces.
 
1859
  ptr2 = strstr(ptr1, "[");
 
1860
  ptr3 = strstr(ptr1, "]");
 
1861
  // If the [] is after the first it isn't the hostname
 
1862
  ptr4 = strstr(ptr1, "/");
 
1863
  if( ptr2!=NULL && ptr3!=NULL && (ptr2 < ptr3) && (!ptr4 || ptr4 > ptr3)) {
 
1864
    // we have an IPv6 numeric address
 
1865
    ptr1++;
 
1866
    pos1++;
 
1867
    ptr2 = ptr3;
 
1868
    v6addr = 1;
 
1869
  } else {
 
1870
    ptr2 = ptr1;  
 
1871
  }
 
1872
 
 
1873
  // look if the port is given
 
1874
  ptr2 = strstr(ptr2, ":");
 
1875
  // If the : is after the first / it isn't the port
 
1876
  ptr3 = strstr(ptr1, "/");
 
1877
  if(ptr3 && ptr3 - ptr2 < 0) ptr2 = NULL;
 
1878
  if( ptr2==NULL ) {
 
1879
    // No port is given
 
1880
    // Look if a path is given
 
1881
    if( ptr3==NULL ) {
 
1882
      // No path/filename
 
1883
      // So we have an URL like http://www.hostname.com
 
1884
      pos2 = strlen(url);
 
1885
    } else {
 
1886
      // We have an URL like http://www.hostname.com/file.txt
 
1887
      pos2 = ptr3-url;
 
1888
    }
 
1889
  } else {
 
1890
    // We have an URL beginning like http://www.hostname.com:1212
 
1891
    // Get the port number
 
1892
    if(!m_option_list_find(desc->fields,"port")) {
 
1893
      mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a port part.\n",name);
 
1894
      // skip
 
1895
    } else {
 
1896
      if(dst) {
 
1897
        int p = atoi(ptr2+1);
 
1898
        char tmp[100];
 
1899
        snprintf(tmp,99,"%d",p);
 
1900
        r = m_struct_set(desc,dst,"port",tmp);
 
1901
        if(r < 0) {
 
1902
          mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting port.\n",name);
 
1903
          return r;
 
1904
        }
 
1905
      }
 
1906
    }
 
1907
    pos2 = ptr2-url;
 
1908
  }
 
1909
  if( v6addr ) pos2--;
 
1910
  // Get the hostname
 
1911
  if(pos2-pos1 > 0) {
 
1912
    if(!m_option_list_find(desc->fields,"hostname")) {
 
1913
      mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a hostname part.\n",name);
 
1914
      // skip
 
1915
    } else {
 
1916
      char tmp[pos2-pos1+1];
 
1917
      strncpy(tmp,ptr1, pos2-pos1);
 
1918
      tmp[pos2-pos1] = '\0';
 
1919
      r = m_struct_set(desc,dst,"hostname",tmp);
 
1920
      if(r < 0) {
 
1921
        mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting hostname.\n",name);
 
1922
        return r;
 
1923
      }
 
1924
    }
 
1925
  }
 
1926
  // Look if a path is given
 
1927
  ptr2 = strstr(ptr1, "/");
 
1928
  if( ptr2!=NULL ) {
 
1929
    // A path/filename is given
 
1930
    // check if it's not a trailing '/'
 
1931
    if( strlen(ptr2)>1 ) {
 
1932
      // copy the path/filename in the URL container
 
1933
      if(!m_option_list_find(desc->fields,"filename")) {
 
1934
        mp_msg(MSGT_CFGPARSER, MSGL_WARN, "Option %s: This URL doesn't have a hostname part.\n",name);
 
1935
        // skip
 
1936
      } else {
 
1937
        if(dst) {
 
1938
          int l = strlen(ptr2+1) + 1;
 
1939
          char* fname = ptr2+1;
 
1940
          if(l > 1) {
 
1941
            fname = malloc(l);
 
1942
            url_unescape_string(fname,ptr2+1);
 
1943
          }
 
1944
          r = m_struct_set(desc,dst,"filename",fname);
 
1945
          if(fname != ptr2+1)
 
1946
            free(fname);
 
1947
          if(r < 0) {
 
1948
            mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Error while setting filename.\n",name);
 
1949
            return r;
 
1950
          }
 
1951
        }
 
1952
      }
 
1953
    }
 
1954
  }
 
1955
  return 1;
 
1956
}
 
1957
 
 
1958
/// TODO : Write the other needed funcs for 'normal' options
 
1959
m_option_type_t m_option_type_custom_url = {
 
1960
  "Custom URL",
 
1961
  "",
 
1962
  0,
 
1963
  0,
 
1964
  parse_custom_url,
 
1965
  NULL,
 
1966
  NULL,
 
1967
  NULL,
 
1968
  NULL,
 
1969
  NULL
 
1970
};