1 /*
2 * Copyright (C) 2000-2005 Chris Ross and various contributors
3 * Copyright (C) 1999-2000 Chris Ross
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * o Redistributions of source code must retain the above copyright notice, this
10 * list of conditions and the following disclaimer.
11 * o Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * o Neither the name of the ferite software nor the names of its contributors may
15 * be used to endorse or promote products derived from this software without
16 * specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifdef HAVE_CONFIG_HEADER
32 #include "../config.h"
33 #endif
34
35 #include "ferite.h"
36 #include "aphex.h"
37
38 #if defined(WIN32) && !defined(USING_MINGW)
39 # include "snprintf.h" /* This is so that we have somethings */
40 #endif
41
42 /**
43 * @group Variables
44 * @description A set of functions to allow for variables to be created and played with. Each of the variable
45 * allocation routines take an argument called alloc, this allows for reduced memory consumption
46 * regarding the names of variables. For a variable name to be static it must be either externally
47 * allocated or a compiled in constant.<nl/>
48 * <nl/>
49 * e.g. "This is static text";<nl/>char *foo = strdup( "This is not (well the result of strdup)" );<nl/>
50 * <nl/>
51 * To make sure that the variable name is allocated simply pass FE_ALLOC, if you want the name to
52 * be set to that of the pointer passed, give the function FE_STATIC.<nl/>
53 */
54
ferite_variable_alloc(FeriteScript * script)55 FeriteVariable *ferite_variable_alloc(FeriteScript *script)
56 {
57 FeriteVariable *ptr;
58
59 FE_ENTER_FUNCTION;
60 if( script && script->vars->stack_ptr )
61 ptr = ferite_stack_pop( script->vars );
62 else
63 ptr = fmalloc( sizeof( FeriteVariable ) );
64
65 FUD(("Allocated Variable %p\n", ptr));
66 ptr->name = NULL;
67 ptr->type = 0;
68 ptr->data.lval = 0;
69 ptr->flags = 0;
70 ptr->index = -1;
71 ptr->lock = NULL;
72 ptr->accessors = NULL;
73 ptr->refcount = 1;
74 ptr->state = FE_ITEM_IS_PUBLIC;
75 FE_LEAVE_FUNCTION( ptr );
76 }
77
78 /**
79 * @function ferite_variable_destroy
80 * @declaration void ferite_variable_destroy( FeriteScript *script, FeriteVariable *var )
81 * @brief Destroy a variable
82 * @param FeriteScript *script The script the variable belongs to
83 * @param FeriteVariable *var The variable to destroy
84 * @description If a variable has got multiple references, the reference will be decremented. Once the reference
85 count reaches 0 (zero) the memory the variable uses will either be handed back to the variable
86 cache or the memory pool.
87 */
ferite_variable_destroy(FeriteScript * script,FeriteVariable * var)88 void ferite_variable_destroy( FeriteScript *script, FeriteVariable *var )
89 {
90 FE_ENTER_FUNCTION;
91 if( var != NULL )
92 {
93 if( --var->refcount > 0 )
94 {
95 if( var->type == F_VAR_OBJ && VAO(var) != NULL )
96 VAO(var)->refcount--;
97 FE_LEAVE_FUNCTION(NOWT);
98 }
99
100 if( var->accessors != NULL )
101 {
102 FUD(( "got accessors\n" ));
103 if( var->accessors->cleanup != NULL && var->accessors->owner )
104 {
105 FUD(( "calling var->cleanup()\n" ));
106 (var->accessors->cleanup)( script, var->accessors->odata );
107 var->accessors->odata = NULL;
108 }
109 ffree( var->accessors );
110 }
111 FUD(("Freeing %s [%p](%s)\n", var->name, var, ferite_variable_id_to_str( script, var->type ) ));
112 switch( var->type )
113 {
114 case F_VAR_STR:
115 FUD(("It's a string. Freeing\n"));
116 ferite_str_destroy( VAS(var) );
117 FUD(("Variable String Data Free'd\n"));
118 break;
119 case F_VAR_OBJ:
120 if( VAO(var) != NULL && !ferite_script_being_deleted( script ) )
121 {
122 /* we only care about reference counting if we are not being deleted */
123 FUD(("Reducing reference count for object variable"));
124 VAO(var)->refcount--;
125 FUD((" :: %d\n", VAO(var)->refcount ));
126 }
127 break;
128 case F_VAR_UARRAY:
129 ferite_uarray_destroy( script, VAUA(var));
130 break;
131 }
132 #ifdef THREAD_SAFE
133 if( var->lock != NULL )
134 {
135 aphex_mutex_destroy( var->lock );
136 var->lock = NULL;
137 }
138 #endif
139 if( !FE_VAR_NAME_IS_STATIC( var ) && var->name != NULL )
140 ffree( var->name );
141
142 FUD(("Variable Name Free'd\n"));
143
144 if( script && script->vars->stack_ptr < script->vars->size-1 )
145 ferite_stack_push( script->vars, var );
146 else
147 ffree( var );
148
149 }
150 FUD(("Variable Free'd\n"));
151 FE_LEAVE_FUNCTION( NOWT );
152 }
153
154 /**
155 * @function ferite_get_variable_ref
156 * @declaration FeriteVariable *ferite_get_variable_ref( FeriteScript *script, FeriteVariable *variable )
157 * @brief Obtain a reference to an existing variable.
158 * @param FeriteScript *script The script context
159 * @param FeriteVariable *variable The variable to obtain a reference count to
160 * @return The same variable pointed to by 'variable'
161 */
ferite_get_variable_ref(FeriteScript * script,FeriteVariable * variable)162 FeriteVariable *ferite_get_variable_ref( FeriteScript *script, FeriteVariable *variable )
163 {
164 FE_ENTER_FUNCTION;
165 if( variable != NULL )
166 {
167 if( variable->type == F_VAR_OBJ && VAO(variable) != NULL )
168 VAO(variable)->refcount++;
169 variable->refcount++;
170 }
171 FE_LEAVE_FUNCTION( variable );
172 }
173
ferite_variable_hash_alloc(FeriteScript * script,int size)174 FeriteVariableHash *ferite_variable_hash_alloc( FeriteScript *script, int size )
175 {
176 FeriteHash *ptr;
177
178 FE_ENTER_FUNCTION;
179 ptr = ferite_create_hash( script, size );
180 FE_LEAVE_FUNCTION( ptr );
181 }
182
183 /**
184 * @function ferite_duplicate_variable
185 * @declaration FeriteVariable *ferite_duplicate_variable( FeriteScript *script, FeriteVariable *var, void *extra )
186 * @brief Duplicate a variable
187 * @param FeriteScript *script The script the variable belongs to
188 * @param FeriteVariable *var The variable to duplicate
189 * @param void *extra Ignore this, just pass NULL to the function
190 * @return A duplicate of the variable
191 */
ferite_duplicate_variable(FeriteScript * script,FeriteVariable * var,void * extra)192 FeriteVariable *ferite_duplicate_variable( FeriteScript *script, FeriteVariable *var, void *extra )
193 {
194 FeriteVariable *ptr = NULL;
195 int alloc;
196 FE_ENTER_FUNCTION;
197 FE_ASSERT( var != NULL );
198 alloc = (FE_VAR_NAME_IS_STATIC( var )) ? FE_STATIC : FE_ALLOC;
199 switch( var->type )
200 {
201 case F_VAR_VOID:
202 ptr = ferite_create_void_variable( script, var->name, alloc );
203 break;
204 case F_VAR_LONG:
205 ptr = ferite_create_number_long_variable( script, var->name, VAI(var), alloc );
206 break;
207 case F_VAR_DOUBLE:
208 ptr = ferite_create_number_double_variable( script, var->name, VAF(var), alloc );
209 break;
210 case F_VAR_STR:
211 ptr = ferite_create_string_variable( script, var->name, VAS(var), alloc );
212 break;
213 case F_VAR_OBJ:
214 ptr = ferite_create_object_variable( script, var->name, alloc );
215 ferite_variable_destroy( script, ferite_op_assign( script, ptr, var ) );
216 break;
217 case F_VAR_UARRAY:
218 ptr = ferite_create_uarray_variable( script, var->name, VAUA(var)->size, alloc );
219 ferite_uarray_destroy( script, VAUA(ptr) );
220 VAUA(ptr) = ferite_uarray_dup( script, VAUA(var), (void *(*)(FeriteScript*,FeriteVariable*,void*))ferite_duplicate_variable );
221 break;
222 case F_VAR_NS:
223 ptr = ferite_create_void_variable( script, var->name, alloc );
224 ptr->type = F_VAR_NS;
225 VAP(ptr) = VAN(var);
226 break;
227 case F_VAR_CLASS:
228 ptr = ferite_create_void_variable( script, var->name, alloc );
229 ptr->type = F_VAR_CLASS;
230 VAP(ptr) = VAC(var);
231 break;
232 default:
233 ferite_error( script, 0, "Can not duplicate variable of type %d", var->type );
234 FE_LEAVE_FUNCTION( ptr );
235 }
236 ptr->flags = var->flags;
237 if( FE_VAR_IS_DISPOSABLE(ptr) )
238 {
239 UNMARK_VARIABLE_AS_DISPOSABLE( ptr );
240 }
241 else
242 {
243 if( var->accessors != NULL )
244 {
245 ptr->accessors = fmalloc( sizeof(FeriteVariableAccessors) );
246 ptr->accessors->get = var->accessors->get;
247 ptr->accessors->set = var->accessors->set;
248 ptr->accessors->cleanup = var->accessors->cleanup;
249 ptr->accessors->odata = var->accessors->odata;
250 ptr->accessors->owner = FE_FALSE;
251 }
252 }
253
254 ptr->state = var->state;
255
256 if( FE_VAR_IS_COMPILED(ptr) )
257 UNMARK_VARIABLE_AS_COMPILED( ptr );
258 ptr->index = var->index;
259 #ifdef THREAD_SAFE
260 if( var->lock != NULL )
261 ptr->lock = (void*)aphex_mutex_recursive_create();
262 #endif
263
264 FE_LEAVE_FUNCTION( ptr );
265 }
266
ferite_duplicate_variable_hash(FeriteScript * script,FeriteVariableHash * hash)267 FeriteVariableHash *ferite_duplicate_variable_hash( FeriteScript *script, FeriteVariableHash *hash )
268 {
269 FeriteVariableHash *ptr = NULL;
270
271 FE_ENTER_FUNCTION;
272 ptr = ferite_hash_dup( script, hash, (void *(*)(FeriteScript *,void *,void*))ferite_duplicate_variable, NULL );
273 FE_LEAVE_FUNCTION( ptr );
274 }
275
ferite_delete_variable_hash(FeriteScript * script,FeriteVariableHash * hash)276 void ferite_delete_variable_hash( FeriteScript *script, FeriteVariableHash *hash )
277 {
278 FE_ENTER_FUNCTION;
279 FE_ASSERT( hash != NULL );
280 ferite_delete_hash( script, hash, (void (*)(FeriteScript *,void *))ferite_variable_destroy );
281 FE_LEAVE_FUNCTION( NOWT );
282 }
283
ferite_add_variable_to_hash(FeriteScript * script,FeriteVariableHash * hash,FeriteVariable * var)284 void ferite_add_variable_to_hash( FeriteScript *script, FeriteVariableHash *hash, FeriteVariable *var )
285 {
286 FE_ENTER_FUNCTION;
287 ferite_hash_add( script, hash, var->name, var );
288 FE_LEAVE_FUNCTION( NOWT );
289 }
290
ferite_get_variable_from_hash(FeriteScript * script,FeriteVariableHash * hash,char * name)291 FeriteVariable *ferite_get_variable_from_hash( FeriteScript *script, FeriteVariableHash *hash, char *name )
292 {
293 FeriteVariable *ptr;
294 FE_ENTER_FUNCTION;
295 ptr = ferite_hash_get( script, hash, name );
296 FE_LEAVE_FUNCTION( ptr );
297 }
298
299 /**
300 * @function ferite_create_string_variable
301 * @declaration FeriteVariable *ferite_create_string_variable( FeriteScript *script, char *name, FeriteString *data, int alloc )
302 * @brief Allocate a FeriteVariable and set it up to be a string from a FeriteString
303 * @param FeriteScript *script The script
304 * @param char *name The name of the variable
305 * @param FeriteString *data The data to set the default value of the variable to
306 * @param int alloc Whether or not to set the variable's name as static or allocated
307 * @return Returns a newly created string variable
308 * @description As ferite's string variable is based upon FeriteString it can happily handle binary data
309 */
ferite_create_string_variable(FeriteScript * script,char * name,FeriteString * data,int alloc)310 FeriteVariable *ferite_create_string_variable( FeriteScript *script, char *name, FeriteString *data, int alloc )
311 {
312 FeriteVariable *ptr;
313
314 FE_ENTER_FUNCTION;
315 ptr = ferite_variable_alloc( script );
316 ptr->type = F_VAR_STR;
317 if( alloc == FE_ALLOC )
318 ptr->name = fstrdup( name );
319 else
320 {
321 ptr->name = name;
322 MARK_VARIABLENAME_AS_STATIC( ptr );
323 }
324 VAS(ptr) = ferite_str_dup( data );
325 FE_LEAVE_FUNCTION( ptr );
326 }
327
328 /**
329 * @function ferite_create_string_variable_from_ptr
330 * @declaration FeriteVariable *ferite_create_string_variable( FeriteScript *script, char *name, char *data, int length, int encoding, int alloc )
331 * @brief Create a FeriteVariable and set it up to be a string from a pointer and length
332 * @param FeriteScript *script The script
333 * @param char *name The name of the variable
334 * @param char *data The data to set the default value of the variable to
335 * @param int length The amount of data that exists - required to be greater than 0 for binary data. For a null terminated string, 0 will cause ferite to work out the length of the data.
336 * @param int encoding The method that was used to encode the string, if you are unsure use FE_CHARSET_DEFAULT
337 * @param int alloc Whether or not to set the variable's name as static or allocated
338 * @return Returns a newly created string variable
339 */
ferite_create_string_variable_from_ptr(FeriteScript * script,char * name,char * data,size_t length,int encoding,int alloc)340 FeriteVariable *ferite_create_string_variable_from_ptr( FeriteScript *script, char *name, char *data, size_t length, int encoding, int alloc )
341 {
342 FeriteVariable *ptr;
343
344 FE_ENTER_FUNCTION;
345 ptr = ferite_variable_alloc( script );
346 ptr->type = F_VAR_STR;
347 if( alloc == FE_ALLOC )
348 ptr->name = fstrdup( name );
349 else
350 {
351 ptr->name = name;
352 MARK_VARIABLENAME_AS_STATIC( ptr );
353 }
354 VAS(ptr) = ferite_str_new( data, length, encoding );
355 FE_LEAVE_FUNCTION( ptr );
356 }
357
358 /**
359 * @function ferite_create_number_long_variable
360 * @declaration FeriteVariable *ferite_create_number_long_variable( FeriteScript *script, char *name, long data, int alloc )
361 * @brief Create a FeriteVariable and set it up to be a number variable of type long
362 * @param FeriteScript *script The script
363 * @param char *name The name of the variable
364 * @param long data The initial value
365 * @param alloc Whether or not to set the variable's name as static or allocated
366 * @return Returns a newly created number variable
367 */
ferite_create_number_long_variable(FeriteScript * script,char * name,long data,int alloc)368 FeriteVariable *ferite_create_number_long_variable( FeriteScript *script, char *name, long data, int alloc )
369 {
370 FeriteVariable *ptr;
371
372 FE_ENTER_FUNCTION;
373 ptr = ferite_variable_alloc( script );
374 ptr->type = F_VAR_LONG;
375 if( alloc == FE_ALLOC )
376 ptr->name = fstrdup( name );
377 else
378 {
379 ptr->name = name;
380 MARK_VARIABLENAME_AS_STATIC( ptr );
381 }
382 VAI( ptr ) = data;
383 FE_LEAVE_FUNCTION( ptr );
384 }
385
386 /**
387 * @function ferite_create_number_double_variable
388 * @declaration FeriteVariable *ferite_create_number_double_variable( FeriteScript *script, char *name, double data, int alloc )
389 * @brief Create a FeriteVariable and set it up to be a number variable of type double
390 * @param FeriteScript *script The script
391 * @param char *name The name of the variable
392 * @param double data The initial value
393 * @param alloc Whether or not to set the variable's name as static or allocated
394 * @return Returns a newly created number variable
395 */
ferite_create_number_double_variable(FeriteScript * script,char * name,double data,int alloc)396 FeriteVariable *ferite_create_number_double_variable( FeriteScript *script, char *name, double data, int alloc )
397 {
398 FeriteVariable *ptr;
399
400 FE_ENTER_FUNCTION;
401 ptr = ferite_variable_alloc( script );
402 ptr->type = F_VAR_DOUBLE;
403 if( alloc == FE_ALLOC )
404 ptr->name = fstrdup( name );
405 else
406 {
407 ptr->name = name;
408 MARK_VARIABLENAME_AS_STATIC( ptr );
409 }
410 VAF( ptr ) = data;
411 FE_LEAVE_FUNCTION( ptr );
412 }
413
414 /**
415 * @function ferite_create_object_variable
416 * @declaration FeriteVariable *ferite_create_object_variable( FeriteScript *script, char *name, int alloc )
417 * @brief Create a FeriteVariable and set it up to be an object variable pointing to 'null'
418 * @param FeriteScript *script The script
419 * @param char *name The name of the variable
420 * @param alloc Whether or not to set the variable's name as static or allocated
421 * @return Returns a newly created object variable
422 */
ferite_create_object_variable(FeriteScript * script,char * name,int alloc)423 FeriteVariable *ferite_create_object_variable( FeriteScript *script, char *name, int alloc )
424 {
425 FeriteVariable *ptr;
426
427 FE_ENTER_FUNCTION;
428 ptr = ferite_variable_alloc( script );
429 ptr->type = F_VAR_OBJ;
430 if( alloc == FE_ALLOC )
431 ptr->name = fstrdup( name );
432 else
433 {
434 ptr->name = name;
435 MARK_VARIABLENAME_AS_STATIC( ptr );
436 }
437 VAO(ptr) = NULL;
438 FE_LEAVE_FUNCTION( ptr );
439 }
440
441 /**
442 * @function ferite_create_object_variable_with_data
443 * @declaration FeriteVariable *ferite_create_object_variable_with_data( FeriteScript *script, char *name, FeriteObject *o, int alloc )
444 * @brief Create a FeriteVariable and set it up to be an object variable pointing to 'o'
445 * @param FeriteScript *script The script
446 * @param char *name The name of the variable
447 * @param alloc Whether or not to set the variable's name as static or allocated
448 * @return Returns a newly created object variable referencing the varuabke that has been passed in.
449 * @description This function can be made to mimic ferite_create_object_variable by passing NULL in for 'o'
450 */
ferite_create_object_variable_with_data(FeriteScript * script,char * name,FeriteObject * o,int alloc)451 FeriteVariable *ferite_create_object_variable_with_data( FeriteScript *script, char *name, FeriteObject *o, int alloc )
452 {
453 FeriteVariable *var = NULL;
454
455 FE_ENTER_FUNCTION;
456 var = ferite_create_object_variable( script, name, alloc );
457 VAO(var) = o;
458 if( VAO(var) != NULL )
459 VAO(var)->refcount++;
460 FE_LEAVE_FUNCTION( var );
461 }
462
463 /**
464 * @function ferite_create_uarray_variable
465 * @declaration FeriteVariable *ferite_create_uarray_variable( FeriteScript *script, char *name, int size, int alloc )
466 * @brief Create a FeriteVariable and set it up to be an array
467 * @param FeriteScript *script The script
468 * @param char *name The name of the variable
469 * @param int size The intial size of the array [This is currently ignored and is taken as a 'hint']
470 * @param int alloc Whether or not to set the variable's name as static or allocated
471 * @return Returns a newly created array variable
472 */
ferite_create_uarray_variable(FeriteScript * script,char * name,int size,int alloc)473 FeriteVariable *ferite_create_uarray_variable( FeriteScript *script, char *name, int size, int alloc )
474 {
475 FeriteVariable *ptr;
476 int rsize = 0;
477
478 FE_ENTER_FUNCTION;
479 rsize = ( size == 0 ) ? FE_ARRAY_DEFAULT_SIZE : size;
480 ptr = ferite_variable_alloc(script);
481 ptr->type = F_VAR_UARRAY;
482 if( alloc == FE_ALLOC )
483 ptr->name = fstrdup( name );
484 else
485 {
486 ptr->name = name;
487 MARK_VARIABLENAME_AS_STATIC( ptr );
488 }
489 VAUA(ptr) = ferite_uarray_create();
490 FE_LEAVE_FUNCTION( ptr );
491 }
492
493 /**
494 * @function ferite_create_void_variable
495 * @declaration FeriteVariable *ferite_create_void_variable( FeriteScript *script, char *name, int alloc )
496 * @brief Create a FeriteVariable and set it up to be an void variable
497 * @param FeriteScript *script The script
498 * @param char *name The name of the variable
499 * @param alloc Whether or not to set the variable's name as static or allocated
500 * @return Returns a newly created void variable
501 */
ferite_create_void_variable(FeriteScript * script,char * name,int alloc)502 FeriteVariable *ferite_create_void_variable( FeriteScript *script, char *name, int alloc )
503 {
504 FeriteVariable *ptr;
505
506 FE_ENTER_FUNCTION;
507 ptr = ferite_variable_alloc(script);
508 ptr->type = F_VAR_VOID;
509 if( alloc == FE_ALLOC )
510 ptr->name = fstrdup( name );
511 else
512 {
513 ptr->name = name;
514 MARK_VARIABLENAME_AS_STATIC( ptr );
515 }
516 FE_LEAVE_FUNCTION( ptr );
517 }
518
519
520 /**
521 * @function ferite_create_class_variable
522 * @declaration FeriteVariable *ferite_create_class_variable( FeriteScript *script, char *name, FeriteClass *klass, int alloc )
523 * @brief Create a variable that references an existing class within the ferite script
524 * @param FeriteScript *script The script context
525 * @param char *name The name of the variable
526 * @param FeriteClass *klass A pointer to the class to reference
527 * @param int alloc Whether or not to allocate the variable name
528 * @return A variable that references the supplied class
529 */
ferite_create_class_variable(FeriteScript * script,char * name,FeriteClass * klass,int alloc)530 FeriteVariable *ferite_create_class_variable( FeriteScript *script, char *name, FeriteClass *klass, int alloc )
531 {
532 FeriteVariable *ptr = NULL;
533
534 FE_ENTER_FUNCTION;
535 ptr = ferite_variable_alloc(script);
536 ptr->type = F_VAR_CLASS;
537 if( alloc == FE_ALLOC )
538 ptr->name = fstrdup( name );
539 else
540 {
541 ptr->name = name;
542 MARK_VARIABLENAME_AS_STATIC( ptr );
543 }
544 ptr->data.pval = klass;
545 FE_LEAVE_FUNCTION( ptr );
546 }
547
548 /**
549 * @function ferite_create_namespace_variable
550 * @declaration FeriteVariable *ferite_create_namespace_variable( FeriteScript *script, char *name, FeriteNamespace *ns, int alloc )
551 * @brief Create a variable that references an existing namespace within the ferite script
552 * @param FeriteScript *script The script context
553 * @param char *name The name of the variable
554 * @param FeriteNamespace *ns A pointer to the namespace to reference
555 * @param int alloc Whether or not to allocate the variable name
556 * @return A variable that references the supplied namespace
557 */
ferite_create_namespace_variable(FeriteScript * script,char * name,FeriteNamespace * ns,int alloc)558 FeriteVariable *ferite_create_namespace_variable( FeriteScript *script, char *name, FeriteNamespace *ns, int alloc )
559 {
560 FeriteVariable *ptr = NULL;
561
562 FE_ENTER_FUNCTION;
563 ptr = ferite_variable_alloc(script);
564 ptr->type = F_VAR_NS;
565 if( alloc == FE_ALLOC )
566 ptr->name = fstrdup( name );
567 else
568 {
569 ptr->name = name;
570 MARK_VARIABLENAME_AS_STATIC( ptr );
571 }
572 ptr->data.pval = ns;
573 FE_LEAVE_FUNCTION( ptr );
574 }
575
ferite_variables_dump(FeriteVariableHash * hash)576 void ferite_variables_dump( FeriteVariableHash *hash )
577 {
578 FE_ENTER_FUNCTION;
579 FE_LEAVE_FUNCTION( NOWT );
580 }
581
582 /**
583 * @function ferite_variable_id_to_str
584 * @declaration char *ferite_variable_id_to_str( FeriteScript *script, int variable )
585 * @brief Get the name of a variable type id
586 * @param FeriteScript *script The script
587 * @param int variable The type of the variable
588 * @return A string, e.g. void, string or number
589 */
ferite_variable_id_to_str(FeriteScript * script,int variable)590 char *ferite_variable_id_to_str( FeriteScript *script, int variable )
591 {
592 FE_ENTER_FUNCTION;
593 switch( variable )
594 {
595 case F_VAR_VOID:
596 FE_LEAVE_FUNCTION( "void" );
597 case F_VAR_STR:
598 FE_LEAVE_FUNCTION( "string" );
599 case F_VAR_LONG:
600 FE_LEAVE_FUNCTION( "number" );
601 case F_VAR_DOUBLE:
602 FE_LEAVE_FUNCTION( "number" );
603 case F_VAR_OBJ:
604 FE_LEAVE_FUNCTION( "object" );
605 case F_VAR_UARRAY:
606 FE_LEAVE_FUNCTION( "array" );
607 case F_VAR_NS:
608 FE_LEAVE_FUNCTION( "namespace" );
609 case F_VAR_CLASS:
610 FE_LEAVE_FUNCTION( "class" );
611 }
612 ferite_error( script, 0, "ERROR: Trying to id variable of type %d - UNKNOWN\n", variable );
613 FE_LEAVE_FUNCTION( NULL );
614 }
615
616 /**
617 * @function ferite_variable_is_false
618 * @declaration int ferite_variable_is_false( FeriteScript *script, FeriteVariable *var )
619 * @brief Find out whether a given FeriteVariable is false
620 * @param FeriteScript *script The script
621 * @param FeriteVariable *var The variable to check
622 * @return FE_TRUE if the variable is false, FE_FALSE otherwise
623 */
ferite_variable_is_false(FeriteScript * script,FeriteVariable * var)624 int ferite_variable_is_false( FeriteScript *script, FeriteVariable *var )
625 {
626 int retval = FE_FALSE;
627
628 FE_ENTER_FUNCTION;
629 if( var != NULL )
630 {
631 switch( var->type )
632 {
633 case F_VAR_VOID:
634 retval = FE_TRUE;
635 break;
636 case F_VAR_LONG:
637 if( VAI(var) == 0 )
638 retval = FE_TRUE;
639 break;
640 case F_VAR_DOUBLE:
641 if( VAF(var) < 0.000001 && VAF(var) > -0.000001 )
642 retval = FE_TRUE;
643 break;
644 case F_VAR_STR:
645 if( FE_STRLEN(var) == 0 )
646 retval = FE_TRUE;
647 break;
648 case F_VAR_OBJ:
649 if( VAO(var) == NULL )
650 retval = FE_TRUE;
651 break;
652 case F_VAR_UARRAY:
653 if( VAUA(var)->size == 0 )
654 retval = FE_TRUE;
655 break;
656 default:
657 ferite_error( script, 0, "Can't tell whether type %d has a truth value", var->type );
658 retval = FE_TRUE;
659 }
660 }
661 else
662 retval = FE_TRUE;
663
664 FE_LEAVE_FUNCTION( retval );
665 }
666
667 /**
668 * @function ferite_number_as_long
669 * @declaration long ferite_number_as_long( FeriteScript *script, FeriteVariable *var )
670 * @brief Provide, for a given variable the long representation.
671 * @param FeriteScript *script The script context
672 * @param FeriteVariable *var The variable to convert
673 * @return The value of the variable
674 * @warning It is important to check script->error_state for ERROR_THROWN. This happens when the variable is not a
675 number type.
676 */
ferite_number_as_long(FeriteScript * script,FeriteVariable * var)677 long ferite_number_as_long( FeriteScript *script, FeriteVariable *var )
678 {
679 FE_ENTER_FUNCTION;
680 FE_ASSERT( var != NULL );
681 if( var->type == F_VAR_LONG )
682 {
683 FE_LEAVE_FUNCTION( VAI(var) );
684 }
685 else if( var->type == F_VAR_DOUBLE )
686 {
687 FE_LEAVE_FUNCTION( (long)VAF(var) );
688 }
689 else
690 ferite_error( script, 0, "Can't convert variable to long\n" );
691 FE_LEAVE_FUNCTION(-1);
692 }
693
694 /**
695 * @function ferite_number_as_double
696 * @declaration double ferite_number_as_double( FeriteScript *script, FeriteVariable *var )
697 * @brief Provide, for a given variable the double representation.
698 * @param FeriteScript *script The script context
699 * @param FeriteVariable *var The variable to convert
700 * @return The value of the variable
701 * @warning It is important to check script->error_state for ERROR_THROWN. This happens when the variable is not a
702 number type.
703 */
ferite_number_as_double(FeriteScript * script,FeriteVariable * var)704 double ferite_number_as_double( FeriteScript *script, FeriteVariable *var )
705 {
706 FE_ENTER_FUNCTION;
707 FE_ASSERT( var != NULL );
708 if( var->type == F_VAR_LONG )
709 {
710 FE_LEAVE_FUNCTION( (double)VAI(var) );
711 }
712 else if( var->type == F_VAR_DOUBLE )
713 {
714 FE_LEAVE_FUNCTION( VAF(var) );
715 }
716 else
717 ferite_error( script, 0, "Can't convert variable to double\n" );
718 FE_LEAVE_FUNCTION(-1);
719 }
720
721 /**
722 * @function ferite_variable_to_str
723 * @declaration FeriteString *ferite_variable_to_str( FeriteScript *script, FeriteVariable *var, int quote )
724 * @brief Get a ferite string representation of a variable
725 * @param FeriteScript *script The script
726 * @param FeriteVariable *var The variable to convert
727 * @param int quote Whether or not to quote the string format. This only applies to string variables.
728 * @return A FeriteString
729 * @description This function works as would be aspected as for all variables but with special behavior for
730 * objects. If there is a .toString() method in the object it will be called with it's results
731 * used as the return value for this function, if the method does not exist then the return will
732 * be a string including the real address of the object along with a statement regarding the
733 * toString method.
734 */
ferite_variable_to_str(FeriteScript * script,FeriteVariable * var,int quote)735 FeriteString *ferite_variable_to_str( FeriteScript *script, FeriteVariable *var, int quote )
736 {
737 FeriteBuffer *buf = NULL;
738 FeriteString *str = NULL;
739 char s[80];
740 int len;
741
742 FE_ENTER_FUNCTION;
743 if( var != NULL )
744 {
745 switch( var->type )
746 {
747 case F_VAR_LONG:
748 len = snprintf( s, 80, "%ld", VAI(var));
749 str = ferite_str_new( s, len, FE_CHARSET_DEFAULT );
750 break;
751 case F_VAR_DOUBLE:
752 len = snprintf( s, 80, "%f", VAF(var));
753 str = ferite_str_new( s, len, FE_CHARSET_DEFAULT );
754 break;
755 case F_VAR_STR:
756 if(quote)
757 {
758 buf = ferite_buffer_new(FE_DEFAULT_BUFFER_SIZE);
759 ferite_buffer_printf(buf,"\"%.*s\"", FE_STRLEN(var),FE_STR2PTR(var));
760 str = ferite_buffer_to_str( buf );
761 }
762 else
763 str = ferite_str_dup( VAS(var) );
764 break;
765 case F_VAR_UARRAY:
766 str = ferite_uarray_to_str(script, VAUA(var));
767 break;
768 case F_VAR_OBJ:
769 {
770 FeriteFunction *toString = NULL;
771 FeriteVariable *retval = NULL;
772 FeriteVariable **params = NULL;
773
774 buf = ferite_buffer_new(FE_DEFAULT_BUFFER_SIZE);
775 if( VAO(var) != NULL )
776 {
777 /* find a .toString() method within the object */
778 if( (toString = ferite_object_get_function_for_params( script, VAO(var), "toString", NULL )) != NULL )
779 {
780 params = ferite_create_parameter_list(2);
781 retval = ferite_call_function( script, VAO(var), NULL, toString, params );
782 /* get the return value */
783 if( retval != NULL )
784 {
785 /* it should be a string */
786 if( retval->type == F_VAR_STR )
787 ferite_buffer_printf( buf, "%.*s", FE_STRLEN(retval), FE_STR2PTR(retval) );
788 else
789 { /* otherwise, lets convert it, but avoid recursion [in case .toString() returns self] */
790 if( retval->type != F_VAR_OBJ || (retval->type == F_VAR_OBJ && VAO(retval) != VAO(var)) )
791 {
792 str = ferite_variable_to_str( script, retval, FE_FALSE );
793 ferite_buffer_printf( buf, "%.*s", str->length, str->data );
794 }
795 else
796 {
797 ferite_buffer_printf( buf, "<object(%s) '%s' 0x%x>", (VAO(retval) != NULL ? VAO(retval)->name : ""),retval->name,VAO(retval));
798 }
799 }
800 ferite_variable_destroy( script, retval );
801 }
802 else
803 {
804 ferite_buffer_printf(buf,"<object(%s) '%s' 0x%x [invalid .toString()]>", (VAO(var) != NULL ? VAO(var)->name : ""),var->name,VAO(var));
805 }
806 ferite_delete_parameter_list( script, params );
807 }
808 else
809 {
810 ferite_buffer_printf(buf,"<object(%s) '%s' 0x%x [no .toString() defined]>", (VAO(var) != NULL ? VAO(var)->name : ""),var->name,VAO(var));
811 }
812 }
813 else
814 {
815 ferite_buffer_printf( buf, "(null)" );
816 }
817 str = ferite_buffer_to_str( buf );
818 }
819 break;
820 case F_VAR_CLASS:
821 {
822 FeriteClass *klass = VAP(var);
823 buf = ferite_buffer_new(FE_DEFAULT_BUFFER_SIZE);
824 ferite_buffer_printf( buf, "<class '%s'%s%s>", klass->name, (klass->parent != NULL?" extends ":""), (klass->parent != NULL?klass->parent->name:"") );
825 str = ferite_buffer_to_str( buf );
826 }
827 break;
828 case F_VAR_NS:
829 {
830 FeriteNamespace *ns = VAP(var);
831 buf = ferite_buffer_new(FE_DEFAULT_BUFFER_SIZE);
832 ferite_buffer_printf( buf, "<namespace '%s'>", ns->name );
833 str = ferite_buffer_to_str( buf );
834 }
835 break;
836 case F_VAR_VOID:
837 str = ferite_str_new( "", strlen(""), FE_CHARSET_DEFAULT );
838 break;
839 default:
840 str = ferite_str_new( "(not a variable)", strlen("(not a variable)"), FE_CHARSET_DEFAULT );
841 }
842 }
843 else
844 {
845 ferite_error( script, 0, "NULL Variable, bad.\n" );
846 str = ferite_str_new( "(no variable)", strlen("(no variable)"), FE_CHARSET_DEFAULT );
847 }
848
849 if( buf != NULL )
850 ferite_buffer_delete(buf);
851 FE_LEAVE_FUNCTION( str );
852 }
853
854 /**
855 * @function ferite_set_variable_name
856 * @declaration void ferite_set_variable_name( FeriteScript *script, FeriteVariable *var, char *newname )
857 * @brief Mark the variable name as allocated and set it
858 * @param FeriteScript *script The script context
859 * @param FeriteVariable *var The variable to apply the name to
860 * @param char *newname The new name to use
861 */
ferite_set_variable_name(FeriteScript * script,FeriteVariable * var,char * newname)862 void ferite_set_variable_name( FeriteScript *script, FeriteVariable *var, char *newname )
863 {
864 FE_ENTER_FUNCTION;
865 if( !FE_VAR_NAME_IS_STATIC( var ) )
866 {
867 ffree( var->name );
868 }
869 else
870 {
871 UNMARK_VARIABLENAME_AS_STATIC( var );
872 }
873 var->name = fstrdup( newname );
874 FE_LEAVE_FUNCTION(NOWT);
875 }
876
877 /**
878 * @function ferite_set_static_variable_name
879 * @declaration void ferite_set_static_variable_name( FeriteScript *script, FeriteVariable *var, char *newname )
880 * @brief Mark the variable name as not allocated and change it to the new name
881 * @param FeriteScript *script The script context
882 * @param FeriteVariable *var The variable to apply the name to
883 * @param char *newname The new name to use
884 */
ferite_set_static_variable_name(FeriteScript * script,FeriteVariable * var,char * newname)885 void ferite_set_static_variable_name( FeriteScript *script, FeriteVariable *var, char *newname )
886 {
887 FE_ENTER_FUNCTION;
888 if( !FE_VAR_NAME_IS_STATIC( var ) )
889 {
890 ffree( var->name );
891 MARK_VARIABLENAME_AS_STATIC( var );
892 }
893 var->name = newname;
894 FE_LEAVE_FUNCTION(NOWT);
895 }
896
897 /**
898 * @function ferite_variable_type_to_char
899 * @declaration char ferite_variable_type_to_char( FeriteScript *script, int type )
900 * @brief For a given variable type, provide the first character of the variable's type.
901 * @param FeriteScript *script The script context
902 * @param int type The variable type
903 * @return A character describing the type.
904 */
ferite_variable_type_to_char(FeriteScript * script,int type)905 char ferite_variable_type_to_char( FeriteScript *script, int type )
906 {
907 char c = ' ';
908
909 FE_ENTER_FUNCTION;
910 switch( type )
911 {
912 case F_VAR_LONG:
913 case F_VAR_DOUBLE:
914 c = 'n';
915 break;
916 case F_VAR_STR:
917 c = 's';
918 break;
919 case F_VAR_OBJ:
920 c = 'o';
921 break;
922 case F_VAR_UARRAY:
923 c = 'a';
924 break;
925 case F_VAR_CLASS:
926 case F_VAR_NS:
927 case F_VAR_VOID:
928 c = 'v';
929 break;
930 }
931 FE_LEAVE_FUNCTION( c );
932 }
933
934
935 /**
936 * @function ferite_types_are_equal
937 * @declaration int ferite_types_are_equal( FeriteScript *script, int typea, int typeb )
938 * @brief Check to see, in ferite's eye, whether or not the two types are equal and can be assigned to
939 * @param FeriteScript *script The script
940 * @param int typea The first type
941 * @param int typeb The second type
942 * @return FE_TRUE if they are considered the same, FE_FALSE otherwise
943 */
ferite_types_are_equal(FeriteScript * script,int typea,int typeb)944 int ferite_types_are_equal( FeriteScript *script, int typea, int typeb )
945 {
946 FE_ENTER_FUNCTION;
947
948 /* Yep they are the same */
949 if( typea == typeb )
950 {
951 FE_LEAVE_FUNCTION( FE_TRUE );
952 }
953
954 /* Check the numbers! */
955 if( typea == F_VAR_LONG && typeb == F_VAR_DOUBLE )
956 {
957 FE_LEAVE_FUNCTION( FE_TRUE );
958 }
959
960 if( typeb == F_VAR_LONG && typea == F_VAR_DOUBLE )
961 {
962 FE_LEAVE_FUNCTION( FE_TRUE );
963 }
964
965 if( typea == F_VAR_VOID )
966 {
967 FE_LEAVE_FUNCTION( FE_TRUE );
968 }
969
970 /* I guess we are SOL */
971 FE_LEAVE_FUNCTION( FE_FALSE );
972 }
973
974 /**
975 * @function ferite_variable_convert_to_type
976 * @declaration void ferite_variable_convert_to_type( FeriteScript *script, FeriteVariable *var, int type )
977 * @brief Convert a variable to another type
978 * @param FeriteScript *script The script
979 * @param FeriteVariable *var The variable to convert
980 * @param int type The type to convert the variable to
981 */
ferite_variable_convert_to_type(FeriteScript * script,FeriteVariable * var,int type)982 void ferite_variable_convert_to_type( FeriteScript *script, FeriteVariable *var, int type )
983 {
984 FE_ENTER_FUNCTION;
985
986 switch( var->type )
987 {
988 case F_VAR_OBJ:
989 if( VAO(var) != NULL )
990 VAO(var)->refcount--;
991 VAO(var) = NULL;
992 break;
993 case F_VAR_STR:
994 ferite_str_destroy( VAS(var) );
995 break;
996 case F_VAR_UARRAY:
997 ferite_uarray_destroy( script, VAUA(var));
998 break;
999 }
1000
1001 var->type = type;
1002 var->data.lval = 0;
1003 FE_LEAVE_FUNCTION(NOWT);
1004 }
1005
ferite_delete_pointer(FeriteScript * script,void * p)1006 void ferite_delete_pointer( FeriteScript *script, void *p )
1007 {
1008 if( p != NULL ) {
1009 ffree( p );
1010 }
1011 }
1012
1013 /**
1014 * @end
1015 */
1016
1017 /**
1018 * @group Variable Accessors
1019 * @description These are used to provide a mechanism for an application to have special
1020 * access to individual variables allowing for transparent control of data
1021 * and lazy updating of information. The mechanism provides three callbacks:
1022 * 'get', 'set', and 'cleanup'. It also provides a means of tagging data to
1023 * variables in a similar fashion of objects with an ->odata pointer that
1024 * is not touched by ferite. Please see include/ferite/fstructs.h for the
1025 * actual structures used.<nl/>
1026 * <nl/>
1027 * <b>How They Work</b><nl/>
1028 * <nl/>
1029 * <b>Get</b><nl/>
1030 * <nl/>
1031 * When a variable is accessed in ferite either to just read or assign - it
1032 * is 'gotten'. This means that in both of the statements below, the variable
1033 * 'foo' it 'gotten'.<nl/>
1034 * <nl/>
1035 * <code>x = bar.foo;<nl/>
1036 * bar.foo = 2 * x;</code><nl/>
1037 * <nl/>
1038 * When a variable is 'gotten', and it has accessors on it, the 'get' method
1039 * will be run on it. This will pass the script and the variable to the method.
1040 * The method can then modify the variable as it wants, and then return. It
1041 * does not return the variable.<nl/>
1042 * <nl/>
1043 * The get function has the prototype:<nl/>
1044 * <nl/>
1045 * <code>void get( FeriteScript *script, FeriteVariable *var )</code>
1046 * <nl/>
1047 * <b>Set</b><nl/>
1048 * <nl/>
1049 * When a variable is assigned to [after it has been gotten], it will have the
1050 * 'set' method called on it, this gets passed the script, the variable and
1051 * the variable that is to be assigned to it [known as RHS var]. Note: ferite
1052 * will already have updated the variable with the RHS var. This means that the
1053 * programmer need only to the minial amount of work. You must not modify the
1054 * rhs variable, it is only given to you so that you can do your own special
1055 * assignment if you _have_ to. I warn against it greatly.<nl/>
1056 * <nl/>
1057 * The set function has the prototype:<nl/>
1058 * <nl/>
1059 * <code>void set( FeriteScript *script, FeriteVariable *lhs, FeriteVariable *rhs )</code>
1060 * <nl/>
1061 * <b>Cleanup</b><nl/>
1062 * <nl/>
1063 * The final mechanism is for cleaning up the ->odata information. It simply
1064 * calls the cleanup function with the script and the ->odata pointer so it
1065 * can be cleaned up.<nl/>
1066 * <nl/>
1067 * The cleanup function has the prototype:<nl/>
1068 * <nl/>
1069 * <tab/>void cleanup( FeriteScript *script, void *odata );<nl/>
1070 * <nl/>
1071 * You need not register all of these. To create the structures on a variable
1072 * call the function:<nl/>
1073 * <nl/>
1074 * <code>void ferite_create_variable_accessors( FeriteScript *script,
1075 * FeriteVariable *var,
1076 * void *get,
1077 * void *set,
1078 * void *cleanup,
1079 * void *odata ) </code>
1080 * <nl/>
1081 * Where 'var' is the variable to attach to, 'get', 'set' and 'cleanup' are
1082 * pointers to the functions, and odata is the initial odata. You can pass the
1083 * function NULL's to just not have them setup.
1084 *
1085 */
1086
1087 /**
1088 * @function ferite_create_variable_accessors
1089 * @declaration void ferite_create_variable_accessors( FeriteScript *script, FeriteVariable *var, void *get, void *set, void *cleanup, void *odata )
1090 * @brief Create the variable accessors
1091 * @param FeriteScript *script The script
1092 * @param FeriteVariable *var The variable to add the accessors to it
1093 * @param void *get A pointer to the get function (can be NULL)
1094 * @param void *set A pointer to the set function (can be NULL)
1095 * @param void *cleanup A pointer to the cleanup function (can be NULL)
1096 * @param void *odata A pointer to some data that can be attached to the variable, ferite does not touch this _AT ALL_
1097 */
ferite_create_variable_accessors(FeriteScript * script,FeriteVariable * var,void * get,void * set,void * cleanup,void * odata)1098 void ferite_create_variable_accessors( FeriteScript *script, FeriteVariable *var, void *get, void *set, void *cleanup, void *odata )
1099 {
1100 FE_ENTER_FUNCTION;
1101 FE_ASSERT( var != NULL );
1102 if( var->accessors == NULL )
1103 var->accessors = fmalloc( sizeof(FeriteVariableAccessors) );
1104 var->accessors->get = get;
1105 var->accessors->set = set;
1106 var->accessors->cleanup = cleanup;
1107 var->accessors->odata = odata;
1108 var->accessors->owner = FE_TRUE;
1109 FE_LEAVE_FUNCTION(NOWT);
1110
1111 }
1112
1113 /**
1114 * @end
1115 */
1116