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 <math.h>
37
38 /**
39 * @group Unified Array
40 * @description This group is to ferite array's what the String group is to ferite strings.
41 */
42
43 /**
44 * @function ferite_uarray_create
45 * @declaration FeriteUnifiedArray *ferite_uarray_create()
46 * @brief Create a new empty array using the compiled in default size
47 * @return A newly allocated FeriteUnifiedArray structure
48 */
ferite_uarray_create()49 FeriteUnifiedArray *ferite_uarray_create()
50 {
51 FeriteUnifiedArray *out = NULL;
52
53 FE_ENTER_FUNCTION;
54 out = fmalloc(sizeof(FeriteUnifiedArray));
55 out->size = 0;
56 out->actual_size = FE_ARRAY_DEFAULT_SIZE;
57 out->hash = ferite_create_hash( NULL, FE_ARRAY_DEFAULT_SIZE );
58 out->array = fmalloc( sizeof(FeriteVariable*) * out->actual_size );
59 out->iteration = -1;
60 out->iterator = NULL;
61 out->iterator_type = 0;
62 FE_LEAVE_FUNCTION( out );
63 }
64
65 /**
66 * @function ferite_uarray_destroy
67 * @declaration void ferite_uarray_destroy( FeriteScript *script, FeriteUnifiedArray *array )
68 * @brief Destroy the array and free up any memory
69 * @param FeriteScript *script The script
70 * @param FeriteUnifiedArray *array The array to delete
71 * @description This function will iterate through the array and destroy each variable. It will then clear up any memory
72 used by the array.
73 */
ferite_uarray_destroy(FeriteScript * script,FeriteUnifiedArray * array)74 void ferite_uarray_destroy( FeriteScript *script, FeriteUnifiedArray *array )
75 {
76 int i;
77
78 FE_ENTER_FUNCTION;
79 FE_ASSERT( array != NULL );
80 FUD(("ARRAY: %p: Deleting array, size %d, actual size %d----------------------------\n", array, array->size, array->actual_size));
81 ferite_delete_hash( script, array->hash, NULL );
82 for( i = 0; i < array->size; i++ )
83 {
84 if( array->array[i] != NULL )
85 {
86 FUD(("ARRYA: Deleting array item %d\n", i ));
87 ferite_variable_destroy( script, array->array[i] );
88 }
89 }
90 if( array->iterator != NULL )
91 ffree( array->iterator );
92 ffree( array->array );
93 ffree( array );
94 FUD(("ARRAY: Done Deleteing array\n" ));
95 FE_LEAVE_FUNCTION( NOWT );
96 }
97
98 /**
99 * @function ferite_uarray_add
100 * @declaration void ferite_uarray_add( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var, char *id, int pos )
101 * @brief Add a variable to the array
102 * @param FeriteScript *script The script
103 * @param FeriteUnifiedArray *array The array to add to
104 * @param FeriteVariable *var The variable to add
105 * @param char *id The hash id
106 * @param int pos The position in the array where the variable should be put
107 * @description The hash id can be NULL - in which case the variable wont be hashed. If it isn't NULL
108 * the variable gets added to the array and also hashed in aswell. The variable can either
109 * be placed at the beginning or at the end of the array. Use either FE_ARRAY_ADD_AT_END
110 * or FE_ARRAY_ADD_AT_START to place the variable at the end or start respectively.
111 */
ferite_uarray_add(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * var,char * id,int pos)112 void ferite_uarray_add( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var, char *id, int pos )
113 {
114 long i = 0;
115
116 FE_ENTER_FUNCTION;
117 FE_ASSERT( array != NULL );
118 /* THIS SHOULD NOT BE ENABLED:
119 if(var->type == F_VAR_OBJ)
120 {
121 if(VAO(var) != NULL)
122 {
123 VAO(var)->refcount++;
124 }
125 } */
126 if( pos > 0 ) /* we either add from the beginning or the end */
127 pos = FE_ARRAY_ADD_AT_END;
128
129 if( id != NULL ) /* add it to the hash */
130 {
131 ferite_set_variable_name( script, var, id );
132 /* We asume that the array is a hash, check against a magic number
133 * to see if we need to grow the number of buckets */
134 if( array->size > array->hash->size * 20 )
135 array->hash = ferite_hash_grow( script, array->hash );
136 ferite_hash_add( script, array->hash, var->name, var );
137 }
138 else
139 {
140 ferite_set_static_variable_name( script, var, "" );
141 }
142
143 if( FE_VAR_IS_DISPOSABLE( var ) )
144 {
145 UNMARK_VARIABLE_AS_DISPOSABLE( var );
146 }
147
148 if( pos == FE_ARRAY_ADD_AT_END )
149 {
150 if( array->size == array->actual_size ) /* we need to bump up the size of the array */
151 {
152 FUD(( " resizing array from %d to %d\n", array->actual_size, array->actual_size * 2 ));
153 array->actual_size *= 2;
154 array->array = frealloc( array->array, sizeof(FeriteVariable*) * array->actual_size );
155 }
156 array->array[array->size] = var;
157 FUD(( " to end slot %d in array %p\n", array->size, array->array ));
158 var->index = array->size;
159 array->size++;
160
161 FE_LEAVE_FUNCTION( NOWT );
162 }
163 if( pos == FE_ARRAY_ADD_AT_START )
164 {
165 if( array->size == array->actual_size ) /* we need to bump up the size of the array */
166 {
167 array->actual_size += FE_ARRAY_DEFAULT_SIZE;
168 array->array = frealloc( array->array, sizeof(FeriteVariable*) * array->actual_size );
169 }
170 /* we need to do a memory move here */
171 FUD(( " shifting array contents\n" ));
172 memmove( array->array + 1, array->array, sizeof(FeriteVariable*) * array->size );
173 /* and insert the stuff here */
174 array->array[0] = var;
175 FUD(( " to slot %d in array %p\n", 0, array->array ));
176 array->size++;
177
178 /* we re-index the variables here. this makes it very very expesive. fun. */
179 for( i = 0; i < array->size; i++ )
180 array->array[i]->index = i;
181
182 FE_LEAVE_FUNCTION( NOWT );
183 }
184 ferite_error( script, 0, "Invalid add position %d\n", pos );
185 FE_LEAVE_FUNCTION( NOWT );
186 }
187
188
189 /**
190 * @function ferite_uarray_set_size
191 * @declaration void ferite_uarray_set_size( FeriteScript *script, FeriteUnifiedArray *array, int size )
192 * @brief This will grow an array to a new size.
193 * @param FeriteScript *script The script context
194 * @param FeriteUnifiedArray *array The array to change
195 * @param int size The new size of the array
196 * @description This function is useful for pre-growing an array where rapid growth is expected - such as filling it
197 with an enormous amount of data. This stops the array having to grow automatically when adding items
198 and can provide a welcome perfomance gain in various scenarios.
199 */
ferite_uarray_set_size(FeriteScript * script,FeriteUnifiedArray * array,int size)200 void ferite_uarray_set_size( FeriteScript *script, FeriteUnifiedArray *array, int size )
201 {
202 int i = array->size;
203
204 FE_ENTER_FUNCTION;
205 if( array->actual_size < size )
206 {
207 array->actual_size = size;
208 array->array = frealloc( array->array, sizeof(FeriteVariable*) * array->actual_size );
209 }
210 for( i = array->size; i < array->actual_size; i++ )
211 array->array[i] = NULL;
212 array->size = size;
213 FE_LEAVE_FUNCTION( NOWT );
214 }
215 /**
216 * @function ferite_uarray_get_index
217 * @declaration FeriteVariable *ferite_uarray_get_index( FeriteScript *script, FeriteUnifiedArray *array, int index )
218 * @brief Get a variable from the array based upon an index
219 * @param FeriteScript *script The script
220 * @param FeriteUnifiedArray *array The array to get the variable from
221 * @param int index The index to obtained
222 * @return The variable if it exists, or NULL otherwise
223 */
ferite_uarray_get_index(FeriteScript * script,FeriteUnifiedArray * array,int index)224 FeriteVariable *ferite_uarray_get_index( FeriteScript *script, FeriteUnifiedArray *array, int index )
225 {
226 FeriteVariable *v = NULL;
227
228 FE_ENTER_FUNCTION;
229 FUD(( "trying to get index %d\n", index ));
230 if( array->size == 0 )
231 {
232 ferite_error( script, 0,"Invalid index: array size is 0\n");
233 FE_LEAVE_FUNCTION( NULL );
234 }
235
236 if(index < 0)
237 {
238 index = array->size + index;
239 }
240
241 if( index >= array->size )
242 {
243 ferite_error( script, 0,"Index %d is out of array's bounds [%d]\n", index, array->size );
244 FE_LEAVE_FUNCTION( NULL );
245 }
246
247 if( array->array[index] == NULL )
248 array->array[index] = ferite_create_void_variable( script, "uvar", FE_STATIC );
249
250 FE_LEAVE_FUNCTION( array->array[index] );
251 }
252
253 /**
254 * @function ferite_uarray_get_from_string
255 * @declaration FeriteVariable *ferite_uarray_get_from_string( FeriteScript *script, FeriteUnifiedArray *array, char *id )
256 * @brief Get the variable from the array based upon a string
257 * @param FeriteScript *script The Script
258 * @param FeriteUnifiedArray *array The array to extract the variable from
259 * @param char *id The name of the variable to get out of the array
260 * @return The variable if it exists or NULL otherwise
261 */
ferite_uarray_get_from_string(FeriteScript * script,FeriteUnifiedArray * array,char * id)262 FeriteVariable *ferite_uarray_get_from_string( FeriteScript *script, FeriteUnifiedArray *array, char *id )
263 {
264 FeriteVariable *ptr = NULL;
265 FE_ENTER_FUNCTION;
266 ptr = ferite_hash_get( script, array->hash, id );
267 FE_LEAVE_FUNCTION(ptr);
268 }
269
270 /**
271 * @function ferite_uarray_delete_from_string
272 * @declaration FeriteVariable *ferite_uarray_delete_from_string( FeriteScript *script, FeriteUnifiedArray *array, char *id )
273 * @brief Delete a value from the array based upon a string
274 * @param FeriteScript *script The Script
275 * @param FeriteUnifiedArray *array The array to delete the variable from
276 * @param char *id The name of the variable to delete out of the array
277 * @return The variable that has been deleted
278 */
ferite_uarray_delete_from_string(FeriteScript * script,FeriteUnifiedArray * array,char * id)279 FeriteVariable *ferite_uarray_delete_from_string( FeriteScript *script, FeriteUnifiedArray *array, char *id )
280 {
281 int real_index = 0;
282
283 FeriteVariable *ptr = NULL;
284 FE_ENTER_FUNCTION;
285 ptr = ferite_hash_get( script, array->hash, id );
286 if( ptr == NULL )
287 {
288 ferite_error( script, 0, "Unknown index '%s'\n", id );
289 FE_LEAVE_FUNCTION(NULL);
290 }
291 real_index = ptr->index;
292 ferite_hash_delete( script, array->hash, id );
293 ferite_uarray_del_index( script, array, real_index );
294 FE_LEAVE_FUNCTION(ptr);
295 }
296
297 /**
298 * @function ferite_uarray_get
299 * @declaration FeriteVariable *ferite_uarray_get( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
300 * @brief Get a variable from an array based upon the value of a FeriteVariable
301 * @param FeriteScript *script The script
302 * @param FeriteUnifiedArray *array The array to get the value from
303 * @param FeriteVariable *var The variable to take the value from
304 * @return The variable if it exists or NULL otherwise
305 */
ferite_uarray_get(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * var)306 FeriteVariable *ferite_uarray_get( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
307 {
308 FE_ENTER_FUNCTION;
309 switch(var->type)
310 {
311 case F_VAR_LONG:
312 FE_LEAVE_FUNCTION( ferite_uarray_get_index( script, array, VAI(var)) );
313 break;
314 case F_VAR_DOUBLE:
315 FE_LEAVE_FUNCTION( ferite_uarray_get_index( script, array, (int)floor(VAF(var)) ) );
316 break;
317 case F_VAR_STR:
318 FE_LEAVE_FUNCTION( ferite_uarray_get_from_string( script, array, FE_STR2PTR(var)) );
319 break;
320 case F_VAR_OBJ:
321 {
322 FeriteVariable *hash_value = NULL, *return_value = NULL;
323 FeriteFunction *hash = ferite_object_get_function_for_params( script, VAO(var), "hash", NULL );
324 hash_value = ferite_call_function( script, VAO(var), NULL, hash, NULL );
325
326 if( hash_value->type != F_VAR_STR )
327 {
328 FE_LEAVE_FUNCTION(NULL);
329 }
330 return_value = ferite_uarray_get_from_string( script, array, FE_STR2PTR(hash_value) );
331 ferite_variable_destroy( script, hash_value );
332 FE_LEAVE_FUNCTION( return_value );
333 }
334 }
335 FE_LEAVE_FUNCTION( NULL );
336 }
337
ferite_uarray_op(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * index,void * rhs)338 FeriteVariable *ferite_uarray_op(FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *index, void *rhs )
339 {
340 FeriteVariable *ptr = NULL;
341
342 FE_ENTER_FUNCTION;
343 if(index->type == F_VAR_VOID && FE_VAR_IS_PLACEHOLDER( index ) )
344 {
345 FUD(( "adding variable to array\n" ));
346 ptr = ferite_create_void_variable( script, "-1", FE_STATIC );
347 ferite_uarray_add( script, array, ptr, NULL, FE_ARRAY_ADD_AT_END );
348 }
349 else
350 {
351 ptr = ferite_uarray_get( script, array, index );
352 if(ptr == NULL)
353 {
354 ptr = ferite_create_void_variable( script, "uvar", FE_STATIC );
355 ferite_uarray_add( script, array, ptr, (index->type == F_VAR_STR ? FE_STR2PTR(index) : NULL ), FE_ARRAY_ADD_AT_END );
356 }
357 }
358 FE_LEAVE_FUNCTION( ptr );
359 }
360
361 /**
362 * @function ferite_uarray_del_var
363 * @declaration void ferite_uarray_del_var( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *index )
364 * @brief Delete a value from an array based upon the value of a FeriteVariable
365 * @param FeriteScript *script The script
366 * @param FeriteUnifiedArray *array The array to delete the value from
367 * @param FeriteVariable *var The variable to take the value from
368 */
ferite_uarray_del_var(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * index)369 void ferite_uarray_del_var( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *index )
370 {
371 int real_index = 0;
372 FeriteVariable *ptr = NULL;
373
374 FE_ENTER_FUNCTION;
375 if( index->type == F_VAR_STR )
376 {
377 ptr = ferite_hash_get( script, array->hash, FE_STR2PTR(index) );
378 if( ptr == NULL )
379 {
380 ferite_error( script, 0, "Unknown index '%s'\n", FE_STR2PTR(index) );
381 FE_LEAVE_FUNCTION(NOWT);
382 }
383 real_index = ptr->index;
384 }
385 else if( index->type == F_VAR_LONG )
386 {
387 real_index = VAI(index);
388 }
389 else if( index->type == F_VAR_DOUBLE )
390 {
391 real_index = (int)floor( VAF(index) );
392 }
393 else
394 {
395 ferite_error( script, 0, "Invalid index type '%s' on array\n", ferite_variable_id_to_str( script, index->type ) );
396 FE_LEAVE_FUNCTION( NOWT );
397 }
398 ferite_uarray_del_index( script, array, real_index );
399 FE_LEAVE_FUNCTION( NOWT );
400 }
401
402 /**
403 * @function ferite_uarray_del_index
404 * @declaration void ferite_uarray_del_index( FeriteScript *script, FeriteUnifiedArray *array, int index )
405 * @brief Delete a value from an array based upon an index
406 * @param FeriteScript *script The script
407 * @param FeriteUnifiedArray *array The array to delete from
408 * @param int index The index to delete
409 */
ferite_uarray_del_index(FeriteScript * script,FeriteUnifiedArray * array,int index)410 void ferite_uarray_del_index( FeriteScript *script, FeriteUnifiedArray *array, int index )
411 {
412 FeriteVariable *var = NULL;
413 long i = 0;
414
415 FE_ENTER_FUNCTION;
416
417 if( index >= array->size || index < 0 )
418 {
419 ferite_error( script, 0, "Index out of bounds %d, can't delete item\n", index );
420 FE_LEAVE_FUNCTION( NOWT );
421 }
422
423 /* delete the entry in the array */
424 var = array->array[index];
425 if( ferite_hash_get( script, array->hash, var->name ) != NULL )
426 ferite_hash_delete( script, array->hash, var->name );
427
428 ferite_variable_destroy( script, var );
429
430 /* we shift the items left one */
431 memmove( array->array + index,
432 array->array + index + 1,
433 (array->size - index) * sizeof(FeriteVariable*) );
434
435 array->size--;
436
437 /* we re-index the variables here. this makes it very very expesive. fun. */
438 for( i = index; i < array->size; i++ )
439 array->array[i]->index = i;
440
441 FE_LEAVE_FUNCTION( NOWT );
442 }
443
444 /**
445 * @function ferite_uarray_dup
446 * @declaration FeriteUnifiedArray *ferite_uarray_dup( FeriteScript *script, FeriteUnifiedArray *array, void *(*ddup)(FeriteScript*,FeriteVariable *data,void*dup) )
447 * @brief Duplicate an array
448 * @param FeriteScript *script The script
449 * @param FeriteUnifiedArray *array The array to duplicate
450 * @param void *dup A function to call to duplicate the variables
451 * @return A copy of the array and it's contents.
452 */
ferite_uarray_dup(FeriteScript * script,FeriteUnifiedArray * array,void * (* ddup)(FeriteScript *,FeriteVariable * data,void * dup))453 FeriteUnifiedArray *ferite_uarray_dup( FeriteScript *script, FeriteUnifiedArray *array, void *(*ddup)(FeriteScript*,FeriteVariable *data,void*dup) )
454 {
455 FeriteUnifiedArray *out;
456 FeriteVariable *ptr = NULL;
457 int i;
458
459 FE_ENTER_FUNCTION;
460 out = fmalloc(sizeof(FeriteUnifiedArray));
461 out->hash = ferite_create_hash( script, array->hash->size );
462 out->size = array->size;
463 out->actual_size = array->actual_size;
464 out->array = fmalloc( sizeof(FeriteVariable*) * out->actual_size );
465
466 /* this will go through and copy the variables, and where needs be add them to the hash */
467 for( i = 0; i < array->size; i++ )
468 {
469 ptr = (ddup)( script, array->array[i], NULL );
470 out->array[i] = ptr;
471 if( ptr->index > -1 && ptr->name[0] != '\0' )
472 ferite_hash_add( script, out->hash, ptr->name, ptr );
473 }
474 out->iteration = -1;
475 out->iterator = NULL;
476 FE_LEAVE_FUNCTION( out );
477 }
478
479 /**
480 * @function ferite_uarray_to_str
481 * @declaration FeriteString *ferite_uarray_to_str( FeriteScript *script, FeriteUnifiedArray *array)
482 * @brief Create a FeriteString based upon the contents of an array
483 * @param FeriteScript *script The script
484 * @param FeriteUnifiedArray *array The array to covert
485 * @return The string version of the array
486 * @description This is useful for converting an array to a string to write to disk, or print out.
487 * The function will recusre and handle inbuild arrays correctly. The output format is
488 the same as the format used when building arrays within a ferite script.
489 */
ferite_uarray_to_str(FeriteScript * script,FeriteUnifiedArray * array)490 FeriteString *ferite_uarray_to_str( FeriteScript *script, FeriteUnifiedArray *array )
491 {
492 FeriteVariable *var;
493 int i;
494 FeriteBuffer *buf;
495 FeriteString *str,*s;
496
497 FE_ENTER_FUNCTION;
498
499 buf = ferite_buffer_new(FE_DEFAULT_BUFFER_SIZE);
500
501 ferite_buffer_add_char(buf, '[');
502
503 for(i = 0; i < array->size; i++)
504 {
505 var = array->array[i];
506 s = ferite_variable_to_str( script, var, 1);
507 if(strcmp("",var->name))
508 {
509 ferite_buffer_printf(buf," '%s' => %.*s",var->name,s->length,s->data);
510 }
511 else
512 {
513 ferite_buffer_add_char(buf, ' ');
514 ferite_buffer_add(buf, s->data, s->length);
515 }
516 ferite_str_destroy( s );
517 if(i < array->size - 1)
518 {
519 ferite_buffer_add_char(buf, ',');
520 }
521 }
522 ferite_buffer_add_char(buf, ' ');
523 ferite_buffer_add_char(buf, ']');
524 str = ferite_buffer_to_str( buf );
525 ferite_buffer_delete(buf);
526 FE_LEAVE_FUNCTION( str );
527 }
528
529 /**
530 * @function ferite_uarray_push
531 * @declaration void ferite_uarray_push( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
532 * @brief Push a value onto the end array like a stack
533 * @param FeriteScript *script The script
534 * @param FeriteUnifiedArray *array The array to push the value onto
535 * @param FeriteVariable *var The variable to push onto the array
536 */
ferite_uarray_push(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * var)537 void ferite_uarray_push( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
538 {
539 FeriteVariable *ptr = NULL;
540
541 FE_ENTER_FUNCTION;
542 ptr = ferite_duplicate_variable( script, var, NULL );
543 ferite_uarray_add( script, array, ptr, NULL, FE_ARRAY_ADD_AT_END );
544 FE_LEAVE_FUNCTION( NOWT );
545 }
546
547 /**
548 * @function ferite_uarray_unshift
549 * @declaration void ferite_uarray_unshift( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
550 * @brief Shift a value onto the front of the array
551 * @param FeriteScript *script The script
552 * @param FeriteUnifiedArray *array The array to shift the value onto
553 * @param FeriteVariable *var The variable to shift onto the array
554 */
ferite_uarray_unshift(FeriteScript * script,FeriteUnifiedArray * array,FeriteVariable * var)555 void ferite_uarray_unshift( FeriteScript *script, FeriteUnifiedArray *array, FeriteVariable *var )
556 {
557 FeriteVariable *v;
558
559 FE_ENTER_FUNCTION;
560 v = ferite_duplicate_variable( script, var, NULL );
561 ferite_uarray_add( script, array, v, NULL, FE_ARRAY_ADD_AT_START );
562 FE_LEAVE_FUNCTION( NOWT );
563 }
564
565 /**
566 * @function ferite_uarray_pop
567 * @declaration FeriteVariable *ferite_uarray_pop( FeriteScript *script, FeriteUnifiedArray *array )
568 * @brief Pop a value off the end of the array and return it
569 * @param FeriteScript *script The script
570 * @param FeriteUnifiedArray *array The array to pop a value off the end
571 */
ferite_uarray_pop(FeriteScript * script,FeriteUnifiedArray * array)572 FeriteVariable *ferite_uarray_pop( FeriteScript *script, FeriteUnifiedArray *array )
573 {
574 FeriteVariable *out = NULL;
575
576 FE_ENTER_FUNCTION;
577 if( array->size > 0 )
578 {
579 out = ferite_duplicate_variable( script, ferite_uarray_get_index( script, array, (array->size) - 1 ), NULL );
580 ferite_uarray_del_index( script, array, (array->size)-1);
581 }
582 else
583 {
584 ferite_warning( script, "Trying to pop element off an empty array!\n" );
585 out = ferite_create_void_variable( script, "no_value", FE_STATIC );
586 }
587 MARK_VARIABLE_AS_DISPOSABLE( out );
588 FE_LEAVE_FUNCTION( out );
589 }
590
591 /**
592 * @function ferite_uarray_shift
593 * @declaration FeriteVariable *ferite_uarray_shift( FeriteScript *script, FeriteUnifiedArray *array )
594 * @brief Shift a value off the front of the array
595 * @param FeriteScript *script The script
596 * @param FeriteUnifiedArray *array The array to shift a value off the front
597 */
ferite_uarray_shift(FeriteScript * script,FeriteUnifiedArray * array)598 FeriteVariable *ferite_uarray_shift( FeriteScript *script, FeriteUnifiedArray *array )
599 {
600 FeriteVariable *out;
601
602 FE_ENTER_FUNCTION;
603 if( array->size > 0 )
604 {
605 out = ferite_duplicate_variable( script, ferite_uarray_get_index( script, array, 0 ), NULL );
606 ferite_uarray_del_index( script, array, 0 );
607 }
608 else
609 {
610 ferite_warning( script, "Trying to shift element off an empty array!\n" );
611 out = ferite_create_void_variable( script, "no_value", FE_STATIC );
612 }
613 MARK_VARIABLE_AS_DISPOSABLE( out );
614 FE_LEAVE_FUNCTION( out );
615 }
616
617 /**
618 * @function ferite_uarray_cmp
619 * @declaration int ferite_uarray_cmp( FeriteScript *script, FeriteUnifiedArray *left, FeriteUnifiedArray *right )
620 * @brief Compare two arrays
621 * @param FeriteScript *script The script
622 * @param FeriteUnifiedArray *left The first array
623 * @param FeriteUnifiedArray *right The second array
624 * @return FE_FALSE if the arrays differ, FE_TRUE otherwise
625 * @description This function checks not only the array elements but also the hash elements of the array.
626 */
ferite_uarray_cmp(FeriteScript * script,FeriteUnifiedArray * left,FeriteUnifiedArray * right)627 int ferite_uarray_cmp( FeriteScript *script, FeriteUnifiedArray *left, FeriteUnifiedArray *right )
628 {
629 int i = 0;
630
631 FE_ENTER_FUNCTION;
632 if( left->size != right->size )
633 {
634 FE_LEAVE_FUNCTION(FE_FALSE);
635 }
636
637 /* go through each element in the array */
638 for( i = 0; i < left->size; i++ )
639 {
640 /* check the type of the variables */
641 if( left->array[i]->type != right->array[i]->type )
642 {
643 FE_LEAVE_FUNCTION(FE_FALSE);
644 }
645
646 #define FE_VAR_TEST( test ) \
647 if( !(test) ){ \
648 FE_LEAVE_FUNCTION(FE_FALSE); \
649 }
650 /* check names match, if they don't ignore it */
651 if( strcmp( left->array[i]->name, right->array[i]->name ) != 0 )
652 {
653 FE_LEAVE_FUNCTION(FE_FALSE);
654 }
655 if( strcmp( left->array[i]->name, "" ) != 0 )
656 {
657 /* they are hashed */
658 if( ferite_hash_get(script,left->hash,left->array[i]->name) == NULL || ferite_hash_get(script,right->hash,right->array[i]->name) == NULL )
659 {
660 FE_LEAVE_FUNCTION(FE_FALSE);
661 }
662 }
663
664 /* check their values */
665 switch( left->array[i]->type )
666 {
667 case F_VAR_LONG:
668 FE_VAR_TEST( VAI(left->array[i]) == VAI(right->array[i]) );
669 break;
670 case F_VAR_DOUBLE:
671 FE_VAR_TEST( VAF(left->array[i]) == VAF(right->array[i]) );
672 break;
673 case F_VAR_STR:
674 FE_VAR_TEST( ferite_str_cmp( VAS(left->array[i]), VAS(right->array[i]) ) == 1 );
675 break;
676 case F_VAR_OBJ:
677 FE_VAR_TEST( VAO(left->array[i]) == VAO(right->array[i]) );
678 break;
679 case F_VAR_UARRAY:
680 FE_VAR_TEST( ferite_uarray_cmp( script, VAUA(left->array[i]), VAUA(right->array[i]) ) == 1 );
681 default:
682 ferite_error( script, 0, "EEEK: unknown type %s in array comparison!\n", ferite_variable_id_to_str( script, left->array[i]->type ) );
683 FE_LEAVE_FUNCTION(FE_FALSE);
684 }
685 #undef FE_VAR_TEST
686 }
687 /* if we have got here they are the same :) */
688 FE_LEAVE_FUNCTION(FE_TRUE);
689 }
690
691 /**
692 * @end
693 */
694