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