Rudimentary arithmetic property assignment
[melted] / src / framework / mlt_properties.c
1 /*
2 * mlt_properties.c -- base properties class
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include "config.h"
22 #include "mlt_properties.h"
23 #include "mlt_property.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 /* ---------------- // Private Implementation // ---------------- */
31
32 /** Private implementation of the property list.
33 */
34
35 typedef struct
36 {
37 int hash[ 199 ];
38 char **name;
39 mlt_property *value;
40 int count;
41 int size;
42 mlt_properties mirror;
43 }
44 property_list;
45
46 /** Memory leak checks.
47 */
48
49 #ifdef _MLT_PROPERTY_CHECKS_
50 static int properties_created = 0;
51 static int properties_destroyed = 0;
52 #endif
53
54 /** Basic implementation.
55 */
56
57 int mlt_properties_init( mlt_properties this, void *child )
58 {
59 if ( this != NULL )
60 {
61 #ifdef _MLT_PROPERTY_CHECKS_
62 // Increment number of properties created
63 properties_created ++;
64 #endif
65
66 // NULL all methods
67 memset( this, 0, sizeof( struct mlt_properties_s ) );
68
69 // Assign the child of the object
70 this->child = child;
71
72 // Allocate the local structure
73 this->local = calloc( sizeof( property_list ), 1 );
74 }
75
76 // Check that initialisation was successful
77 return this != NULL && this->local == NULL;
78 }
79
80 /** Constructor for stand alone object.
81 */
82
83 mlt_properties mlt_properties_new( )
84 {
85 // Construct a standalone properties object
86 mlt_properties this = calloc( sizeof( struct mlt_properties_s ), 1 );
87
88 // Initialise this
89 mlt_properties_init( this, NULL );
90
91 // Return the pointer
92 return this;
93 }
94
95 /** Load properties from a file.
96 */
97
98 mlt_properties mlt_properties_load( char *filename )
99 {
100 // Construct a standalone properties object
101 mlt_properties this = mlt_properties_new( );
102
103 if ( this != NULL )
104 {
105 // Open the file
106 FILE *file = fopen( filename, "r" );
107
108 // Load contents of file
109 if ( file != NULL )
110 {
111 // Temp string
112 char temp[ 1024 ];
113
114 // Read each string from the file
115 while( fgets( temp, 1024, file ) )
116 {
117 // Chomp the string
118 temp[ strlen( temp ) - 1 ] = '\0';
119
120 // Parse and set the property
121 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
122 mlt_properties_parse( this, temp );
123 }
124
125 // Close the file
126 fclose( file );
127 }
128 }
129
130 // Return the pointer
131 return this;
132 }
133
134 static inline int generate_hash( char *name )
135 {
136 int hash = 0;
137 int i = 1;
138 while ( *name )
139 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
140 return hash;
141 }
142
143 /** Special case - when a container (such as fezzik) is protecting another
144 producer, we need to ensure that properties are passed through to the
145 real producer.
146 */
147
148 static inline void mlt_properties_do_mirror( mlt_properties this, char *name )
149 {
150 property_list *list = this->local;
151 if ( list->mirror != NULL )
152 {
153 char *value = mlt_properties_get( this, name );
154 if ( value != NULL )
155 mlt_properties_set( list->mirror, name, value );
156 }
157 }
158
159 /** Allow the specification of a mirror.
160 */
161
162 void mlt_properties_mirror( mlt_properties this, mlt_properties that )
163 {
164 property_list *list = this->local;
165 list->mirror = that;
166 }
167
168 /** Inherit all serialisable properties from that into this.
169 */
170
171 int mlt_properties_inherit( mlt_properties this, mlt_properties that )
172 {
173 int count = mlt_properties_count( that );
174 int i = 0;
175 for ( i = 0; i < count; i ++ )
176 {
177 char *value = mlt_properties_get_value( that, i );
178 if ( value != NULL )
179 {
180 char *name = mlt_properties_get_name( that, i );
181 mlt_properties_set( this, name, value );
182 }
183 }
184 return 0;
185 }
186
187 /** Pass all properties from 'that' that match the prefix to 'this' (excluding the prefix).
188 */
189
190 int mlt_properties_pass( mlt_properties this, mlt_properties that, char *prefix )
191 {
192 int count = mlt_properties_count( that );
193 int length = strlen( prefix );
194 int i = 0;
195 for ( i = 0; i < count; i ++ )
196 {
197 char *name = mlt_properties_get_name( that, i );
198 if ( !strncmp( name, prefix, length ) )
199 {
200 char *value = mlt_properties_get_value( that, i );
201 if ( value != NULL )
202 mlt_properties_set( this, name + length, value );
203 }
204 }
205 return 0;
206 }
207
208 /** Locate a property by name
209 */
210
211 static inline mlt_property mlt_properties_find( mlt_properties this, char *name )
212 {
213 property_list *list = this->local;
214 mlt_property value = NULL;
215 int key = generate_hash( name );
216 int i = list->hash[ key ] - 1;
217
218 if ( i >= 0 )
219 {
220 // Check if we're hashed
221 if ( list->count > 0 &&
222 name[ 0 ] == list->name[ i ][ 0 ] &&
223 !strcmp( list->name[ i ], name ) )
224 value = list->value[ i ];
225
226 // Locate the item
227 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
228 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
229 value = list->value[ i ];
230 }
231
232 return value;
233 }
234
235 /** Add a new property.
236 */
237
238 static mlt_property mlt_properties_add( mlt_properties this, char *name )
239 {
240 property_list *list = this->local;
241 int key = generate_hash( name );
242
243 // Check that we have space and resize if necessary
244 if ( list->count == list->size )
245 {
246 list->size += 50;
247 list->name = realloc( list->name, list->size * sizeof( char * ) );
248 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
249 }
250
251 // Assign name/value pair
252 list->name[ list->count ] = strdup( name );
253 list->value[ list->count ] = mlt_property_init( );
254
255 // Assign to hash table
256 if ( list->hash[ key ] == 0 )
257 list->hash[ key ] = list->count + 1;
258
259 // Return and increment count accordingly
260 return list->value[ list->count ++ ];
261 }
262
263 /** Fetch a property by name - this includes add if not found.
264 */
265
266 static mlt_property mlt_properties_fetch( mlt_properties this, char *name )
267 {
268 // Try to find an existing property first
269 mlt_property property = mlt_properties_find( this, name );
270
271 // If it wasn't found, create one
272 if ( property == NULL )
273 property = mlt_properties_add( this, name );
274
275 // Return the property
276 return property;
277 }
278
279 /** Set the property.
280 */
281
282 int mlt_properties_set( mlt_properties this, char *name, char *value )
283 {
284 int error = 1;
285
286 // Fetch the property to work with
287 mlt_property property = mlt_properties_fetch( this, name );
288
289 // Set it if not NULL
290 if ( property != NULL && ( value == NULL || value[ 0 ] != '@' ) )
291 {
292 error = mlt_property_set_string( property, value );
293 mlt_properties_do_mirror( this, name );
294 }
295 else if ( property != NULL && value[ 0 ] == '@' )
296 {
297 int total = 0;
298 int current = 0;
299 char id[ 255 ];
300 char op = '+';
301
302 value ++;
303
304 while ( *value != '\0' )
305 {
306 int length = strcspn( value, "+-*/" );
307
308 // Get the identifier
309 strncpy( id, value, length );
310 id[ length ] = '\0';
311 value += length;
312
313 // Determine the value
314 if ( isdigit( id[ 0 ] ) )
315 current = atof( id );
316 else
317 current = mlt_properties_get_int( this, id );
318
319 // Apply the operation
320 switch( op )
321 {
322 case '+':
323 total += current;
324 break;
325 case '-':
326 total -= current;
327 break;
328 case '*':
329 total *= current;
330 break;
331 case '/':
332 total /= current;
333 break;
334 }
335
336 // Get the next op
337 op = *value != '\0' ? *value ++ : ' ';
338 }
339
340 error = mlt_property_set_int( property, total );
341 mlt_properties_do_mirror( this, name );
342 }
343
344 return error;
345 }
346
347 /** Set or default the property.
348 */
349
350 int mlt_properties_set_or_default( mlt_properties this, char *name, char *value, char *def )
351 {
352 return mlt_properties_set( this, name, value == NULL ? def : value );
353 }
354
355 /** Get a string value by name.
356 */
357
358 char *mlt_properties_get( mlt_properties this, char *name )
359 {
360 mlt_property value = mlt_properties_find( this, name );
361 return value == NULL ? NULL : mlt_property_get_string( value );
362 }
363
364 /** Get a name by index.
365 */
366
367 char *mlt_properties_get_name( mlt_properties this, int index )
368 {
369 property_list *list = this->local;
370 if ( index >= 0 && index < list->count )
371 return list->name[ index ];
372 return NULL;
373 }
374
375 /** Get a string value by index.
376 */
377
378 char *mlt_properties_get_value( mlt_properties this, int index )
379 {
380 property_list *list = this->local;
381 if ( index >= 0 && index < list->count )
382 return mlt_property_get_string( list->value[ index ] );
383 return NULL;
384 }
385
386 /** Get a data value by index.
387 */
388
389 void *mlt_properties_get_data_at( mlt_properties this, int index, int *size )
390 {
391 property_list *list = this->local;
392 if ( index >= 0 && index < list->count )
393 return mlt_property_get_data( list->value[ index ], size );
394 return NULL;
395 }
396
397 /** Return the number of items in the list.
398 */
399
400 int mlt_properties_count( mlt_properties this )
401 {
402 property_list *list = this->local;
403 return list->count;
404 }
405
406 /** Set a value by parsing a name=value string
407 */
408
409 int mlt_properties_parse( mlt_properties this, char *namevalue )
410 {
411 char *name = strdup( namevalue );
412 char *value = NULL;
413 int error = 0;
414 char *ptr = strchr( name, '=' );
415
416 if ( ptr )
417 {
418 *( ptr ++ ) = '\0';
419
420 if ( *ptr != '\"' )
421 {
422 value = strdup( ptr );
423 }
424 else
425 {
426 ptr ++;
427 value = strdup( ptr );
428 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
429 value[ strlen( value ) - 1 ] = '\0';
430 }
431 }
432 else
433 {
434 value = strdup( "" );
435 }
436
437 error = mlt_properties_set( this, name, value );
438
439 free( name );
440 free( value );
441
442 return error;
443 }
444
445 /** Get a value associated to the name.
446 */
447
448 int mlt_properties_get_int( mlt_properties this, char *name )
449 {
450 mlt_property value = mlt_properties_find( this, name );
451 return value == NULL ? 0 : mlt_property_get_int( value );
452 }
453
454 /** Set a value associated to the name.
455 */
456
457 int mlt_properties_set_int( mlt_properties this, char *name, int value )
458 {
459 int error = 1;
460
461 // Fetch the property to work with
462 mlt_property property = mlt_properties_fetch( this, name );
463
464 // Set it if not NULL
465 if ( property != NULL )
466 {
467 error = mlt_property_set_int( property, value );
468 mlt_properties_do_mirror( this, name );
469 }
470
471 return error;
472 }
473
474 /** Get a value associated to the name.
475 */
476
477 double mlt_properties_get_double( mlt_properties this, char *name )
478 {
479 mlt_property value = mlt_properties_find( this, name );
480 return value == NULL ? 0 : mlt_property_get_double( value );
481 }
482
483 /** Set a value associated to the name.
484 */
485
486 int mlt_properties_set_double( mlt_properties this, char *name, double value )
487 {
488 int error = 1;
489
490 // Fetch the property to work with
491 mlt_property property = mlt_properties_fetch( this, name );
492
493 // Set it if not NULL
494 if ( property != NULL )
495 {
496 error = mlt_property_set_double( property, value );
497 mlt_properties_do_mirror( this, name );
498 }
499
500 return error;
501 }
502
503 /** Get a value associated to the name.
504 */
505
506 mlt_position mlt_properties_get_position( mlt_properties this, char *name )
507 {
508 mlt_property value = mlt_properties_find( this, name );
509 return value == NULL ? 0 : mlt_property_get_position( value );
510 }
511
512 /** Set a value associated to the name.
513 */
514
515 int mlt_properties_set_position( mlt_properties this, char *name, mlt_position value )
516 {
517 int error = 1;
518
519 // Fetch the property to work with
520 mlt_property property = mlt_properties_fetch( this, name );
521
522 // Set it if not NULL
523 if ( property != NULL )
524 {
525 error = mlt_property_set_position( property, value );
526 mlt_properties_do_mirror( this, name );
527 }
528
529 return error;
530 }
531
532 /** Get a value associated to the name.
533 */
534
535 void *mlt_properties_get_data( mlt_properties this, char *name, int *length )
536 {
537 mlt_property value = mlt_properties_find( this, name );
538 return value == NULL ? NULL : mlt_property_get_data( value, length );
539 }
540
541 /** Set a value associated to the name.
542 */
543
544 int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
545 {
546 int error = 1;
547
548 // Fetch the property to work with
549 mlt_property property = mlt_properties_fetch( this, name );
550
551 // Set it if not NULL
552 if ( property != NULL )
553 error = mlt_property_set_data( property, value, length, destroy, serialise );
554
555 return error;
556 }
557
558 /** Rename a property.
559 */
560
561 int mlt_properties_rename( mlt_properties this, char *source, char *dest )
562 {
563 mlt_property value = mlt_properties_find( this, dest );
564
565 if ( value == NULL )
566 {
567 property_list *list = this->local;
568 int i = 0;
569
570 // Locate the item
571 for ( i = 0; i < list->count; i ++ )
572 {
573 if ( !strcmp( list->name[ i ], source ) )
574 {
575 free( list->name[ i ] );
576 list->name[ i ] = strdup( dest );
577 list->hash[ generate_hash( dest ) ] = i + 1;
578 break;
579 }
580 }
581 }
582
583 return value != NULL;
584 }
585
586 /** Dump the properties.
587 */
588
589 void mlt_properties_dump( mlt_properties this, FILE *output )
590 {
591 property_list *list = this->local;
592 int i = 0;
593 for ( i = 0; i < list->count; i ++ )
594 if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
595 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
596 }
597
598 /** Close the list.
599 */
600
601 void mlt_properties_close( mlt_properties this )
602 {
603 if ( this != NULL )
604 {
605 property_list *list = this->local;
606 int index = 0;
607
608 // Clean up names and values
609 for ( index = list->count - 1; index >= 0; index -- )
610 {
611 free( list->name[ index ] );
612 mlt_property_close( list->value[ index ] );
613 }
614
615 // Clear up the list
616 free( list->name );
617 free( list->value );
618 free( list );
619
620 // Free this now if this has no child
621 if ( this->child == NULL )
622 free( this );
623
624 #ifdef _MLT_PROPERTY_CHECKS_
625 // Increment destroyed count
626 properties_destroyed ++;
627
628 // Show current stats - these should match when the app is closed
629 fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
630 #endif
631 }
632 }
633