1 /* Array manipulation routines for S-Lang */
2 /* Copyright (c) 1997, 1999, 2001, 2002 John E. Davis
3 * This file is part of the S-Lang library.
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Perl Artistic License.
7 */
8
9 #include "slinclud.h"
10
11 /* #define SL_APP_WANTS_FOREACH */
12 #include "slang.h"
13 #include "_slang.h"
14
15 typedef struct
16 {
17 int first_index;
18 int last_index;
19 int delta;
20 }
21 SLarray_Range_Array_Type;
22
23 /* Use SLang_pop_array when a linear array is required. */
pop_array(SLang_Array_Type ** at_ptr,int convert_scalar)24 static int pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
25 {
26 SLang_Array_Type *at;
27 int one = 1;
28 int type;
29
30 *at_ptr = NULL;
31 type = SLang_peek_at_stack ();
32
33 switch (type)
34 {
35 case -1:
36 return -1;
37
38 case SLANG_ARRAY_TYPE:
39 return SLclass_pop_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR *) at_ptr);
40
41 case SLANG_NULL_TYPE:
42 convert_scalar = 0;
43 /* drop */
44 default:
45 if (convert_scalar == 0)
46 {
47 SLdo_pop ();
48 SLang_verror (SL_TYPE_MISMATCH, "Context requires an array. Scalar not converted");
49 return -1;
50 }
51 break;
52 }
53
54 if (NULL == (at = SLang_create_array ((unsigned char) type, 0, NULL, &one, 1)))
55 return -1;
56
57 if (-1 == at->cl->cl_apop ((unsigned char) type, at->data))
58 {
59 SLang_free_array (at);
60 return -1;
61 }
62
63 *at_ptr = at;
64
65 return 0;
66 }
67
linear_get_data_addr(SLang_Array_Type * at,int * dims)68 static VOID_STAR linear_get_data_addr (SLang_Array_Type *at, int *dims)
69 {
70 unsigned int num_dims;
71 unsigned int ofs;
72 unsigned int i;
73 int *max_dims;
74
75 ofs = 0;
76 max_dims = at->dims;
77 num_dims = at->num_dims;
78
79 for (i = 0; i < num_dims; i++)
80 {
81 int d = dims[i];
82
83 if (d < 0)
84 d = d + max_dims[i];
85
86 ofs = ofs * (unsigned int)max_dims [i] + (unsigned int) d;
87 }
88
89 return (VOID_STAR) ((char *)at->data + (ofs * at->sizeof_type));
90 }
91
get_data_addr(SLang_Array_Type * at,int * dims)92 static VOID_STAR get_data_addr (SLang_Array_Type *at, int *dims)
93 {
94 VOID_STAR data;
95
96 data = at->data;
97 if (data == NULL)
98 {
99 SLang_verror (SL_UNKNOWN_ERROR, "Array has no data");
100 return NULL;
101 }
102
103 data = (*at->index_fun) (at, dims);
104
105 if (data == NULL)
106 {
107 SLang_verror (SL_UNKNOWN_ERROR, "Unable to access array element");
108 return NULL;
109 }
110
111 return data;
112 }
113
_SLarray_free_array_elements(SLang_Class_Type * cl,VOID_STAR s,unsigned int num)114 void _SLarray_free_array_elements (SLang_Class_Type *cl, VOID_STAR s, unsigned int num)
115 {
116 unsigned int sizeof_type;
117 void (*f) (unsigned char, VOID_STAR);
118 char *p;
119 unsigned char type;
120
121 if ((cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
122 || (cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR))
123 return;
124
125 f = cl->cl_destroy;
126 sizeof_type = cl->cl_sizeof_type;
127 type = cl->cl_data_type;
128
129 p = (char *) s;
130 while (num != 0)
131 {
132 if (NULL != *(VOID_STAR *)p)
133 {
134 (*f) (type, (VOID_STAR)p);
135 *(VOID_STAR *) p = NULL;
136 }
137 p += sizeof_type;
138 num--;
139 }
140 }
141
destroy_element(SLang_Array_Type * at,int * dims,VOID_STAR data)142 static int destroy_element (SLang_Array_Type *at,
143 int *dims,
144 VOID_STAR data)
145 {
146 data = get_data_addr (at, dims);
147 if (data == NULL)
148 return -1;
149
150 /* This function should only get called for arrays that have
151 * pointer elements. Do not call the destroy method if the element
152 * is NULL.
153 */
154 if (NULL != *(VOID_STAR *)data)
155 {
156 (*at->cl->cl_destroy) (at->data_type, data);
157 *(VOID_STAR *) data = NULL;
158 }
159 return 0;
160 }
161
162 /* This function only gets called when a new array is created. Thus there
163 * is no need to destroy the object first.
164 */
new_object_element(SLang_Array_Type * at,int * dims,VOID_STAR data)165 static int new_object_element (SLang_Array_Type *at,
166 int *dims,
167 VOID_STAR data)
168 {
169 data = get_data_addr (at, dims);
170 if (data == NULL)
171 return -1;
172
173 return (*at->cl->cl_init_array_object) (at->data_type, data);
174 }
175
next_index(int * dims,int * max_dims,unsigned int num_dims)176 static int next_index (int *dims, int *max_dims, unsigned int num_dims)
177 {
178 while (num_dims)
179 {
180 int dims_i;
181
182 num_dims--;
183
184 dims_i = dims [num_dims] + 1;
185 if (dims_i != (int) max_dims [num_dims])
186 {
187 dims [num_dims] = dims_i;
188 return 0;
189 }
190 dims [num_dims] = 0;
191 }
192
193 return -1;
194 }
195
do_method_for_all_elements(SLang_Array_Type * at,int (* method)(SLang_Array_Type *,int *,VOID_STAR),VOID_STAR client_data)196 static int do_method_for_all_elements (SLang_Array_Type *at,
197 int (*method)(SLang_Array_Type *,
198 int *,
199 VOID_STAR),
200 VOID_STAR client_data)
201 {
202 int dims [SLARRAY_MAX_DIMS];
203 int *max_dims;
204 unsigned int num_dims;
205
206 if (at->num_elements == 0)
207 return 0;
208
209 max_dims = at->dims;
210 num_dims = at->num_dims;
211
212 SLMEMSET((char *)dims, 0, sizeof(dims));
213
214 do
215 {
216 if (-1 == (*method) (at, dims, client_data))
217 return -1;
218 }
219 while (0 == next_index (dims, max_dims, num_dims));
220
221 return 0;
222 }
223
SLang_free_array(SLang_Array_Type * at)224 void SLang_free_array (SLang_Array_Type *at)
225 {
226 unsigned int flags;
227
228 if (at == NULL) return;
229
230 if (at->num_refs > 1)
231 {
232 at->num_refs -= 1;
233 return;
234 }
235
236 flags = at->flags;
237
238 if (flags & SLARR_DATA_VALUE_IS_INTRINSIC)
239 return; /* not to be freed */
240
241 if (flags & SLARR_DATA_VALUE_IS_POINTER)
242 (void) do_method_for_all_elements (at, destroy_element, NULL);
243
244 if (at->free_fun != NULL)
245 at->free_fun (at);
246 else
247 SLfree ((char *) at->data);
248
249 SLfree ((char *) at);
250 }
251
252 SLang_Array_Type *
SLang_create_array1(unsigned char type,int read_only,VOID_STAR data,int * dims,unsigned int num_dims,int no_init)253 SLang_create_array1 (unsigned char type, int read_only, VOID_STAR data,
254 int *dims, unsigned int num_dims, int no_init)
255 {
256 SLang_Class_Type *cl;
257 unsigned int i;
258 SLang_Array_Type *at;
259 unsigned int num_elements;
260 unsigned int sizeof_type;
261 unsigned int size;
262
263 if (num_dims > SLARRAY_MAX_DIMS)
264 {
265 SLang_verror (SL_NOT_IMPLEMENTED, "%u dimensional arrays are not supported", num_dims);
266 return NULL;
267 }
268
269 for (i = 0; i < num_dims; i++)
270 {
271 if (dims[i] < 0)
272 {
273 SLang_verror (SL_INVALID_PARM, "Size of array dim %u is less than 0", i);
274 return NULL;
275 }
276 }
277
278 cl = _SLclass_get_class (type);
279
280 at = (SLang_Array_Type *) SLmalloc (sizeof(SLang_Array_Type));
281 if (at == NULL)
282 return NULL;
283
284 SLMEMSET ((char*) at, 0, sizeof(SLang_Array_Type));
285
286 at->data_type = type;
287 at->cl = cl;
288 at->num_dims = num_dims;
289 at->num_refs = 1;
290
291 if (read_only) at->flags = SLARR_DATA_VALUE_IS_READ_ONLY;
292 switch (cl->cl_class_type)
293 {
294 case SLANG_CLASS_TYPE_VECTOR:
295 case SLANG_CLASS_TYPE_SCALAR:
296 break;
297
298 default:
299 at->flags |= SLARR_DATA_VALUE_IS_POINTER;
300 }
301
302 num_elements = 1;
303 for (i = 0; i < num_dims; i++)
304 {
305 at->dims [i] = dims[i];
306 num_elements = dims [i] * num_elements;
307 }
308
309 /* Now set the rest of the unused dimensions to 1. This makes it easier
310 * when transposing arrays.
311 */
312 while (i < SLARRAY_MAX_DIMS)
313 at->dims[i++] = 1;
314
315 at->num_elements = num_elements;
316 at->index_fun = linear_get_data_addr;
317 at->sizeof_type = sizeof_type = cl->cl_sizeof_type;
318
319 if (data != NULL)
320 {
321 at->data = data;
322 return at;
323 }
324
325 size = num_elements * sizeof_type;
326
327 if (size == 0) size = 1;
328
329 if (NULL == (data = (VOID_STAR) SLmalloc (size)))
330 {
331 SLang_free_array (at);
332 return NULL;
333 }
334
335 if (no_init == 0)
336 SLMEMSET ((char *) data, 0, size);
337
338 at->data = data;
339
340 if ((cl->cl_init_array_object != NULL)
341 && (-1 == do_method_for_all_elements (at, new_object_element, NULL)))
342 {
343 SLang_free_array (at);
344 return NULL;
345 }
346 return at;
347 }
348
349 SLang_Array_Type *
SLang_create_array(unsigned char type,int read_only,VOID_STAR data,int * dims,unsigned int num_dims)350 SLang_create_array (unsigned char type, int read_only, VOID_STAR data,
351 int *dims, unsigned int num_dims)
352 {
353 return SLang_create_array1 (type, read_only, data, dims, num_dims, 0);
354 }
355
SLang_add_intrinsic_array(char * name,unsigned char type,int read_only,VOID_STAR data,unsigned int num_dims,...)356 int SLang_add_intrinsic_array (char *name,
357 unsigned char type,
358 int read_only,
359 VOID_STAR data,
360 unsigned int num_dims, ...)
361 {
362 va_list ap;
363 unsigned int i;
364 int dims[SLARRAY_MAX_DIMS];
365 SLang_Array_Type *at;
366
367 if ((num_dims > SLARRAY_MAX_DIMS)
368 || (name == NULL)
369 || (data == NULL))
370 {
371 SLang_verror (SL_INVALID_PARM, "Unable to create intrinsic array");
372 return -1;
373 }
374
375 va_start (ap, num_dims);
376 for (i = 0; i < num_dims; i++)
377 dims [i] = va_arg (ap, int);
378 va_end (ap);
379
380 at = SLang_create_array (type, read_only, data, dims, num_dims);
381 if (at == NULL)
382 return -1;
383 at->flags |= SLARR_DATA_VALUE_IS_INTRINSIC;
384
385 /* Note: The variable that refers to the intrinsic array is regarded as
386 * read-only. That way, Array_Name = another_array; will fail.
387 */
388 if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) at, SLANG_ARRAY_TYPE, 1))
389 {
390 SLang_free_array (at);
391 return -1;
392 }
393 return 0;
394 }
395
pop_array_indices(int * dims,unsigned int num_dims)396 static int pop_array_indices (int *dims, unsigned int num_dims)
397 {
398 unsigned int n;
399 int i;
400
401 if (num_dims > SLARRAY_MAX_DIMS)
402 {
403 SLang_verror (SL_INVALID_PARM, "Array size not supported");
404 return -1;
405 }
406
407 n = num_dims;
408 while (n != 0)
409 {
410 n--;
411 if (-1 == SLang_pop_integer (&i))
412 return -1;
413
414 dims[n] = i;
415 }
416
417 return 0;
418 }
419
SLang_push_array(SLang_Array_Type * at,int free_flag)420 int SLang_push_array (SLang_Array_Type *at, int free_flag)
421 {
422 if (at == NULL)
423 return SLang_push_null ();
424
425 at->num_refs += 1;
426
427 if (0 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR) at))
428 {
429 if (free_flag)
430 SLang_free_array (at);
431 return 0;
432 }
433
434 at->num_refs -= 1;
435
436 if (free_flag) SLang_free_array (at);
437 return -1;
438 }
439
440 /* This function gets called via expressions such as Double_Type[10, 20];
441 */
push_create_new_array(void)442 static int push_create_new_array (void)
443 {
444 unsigned int num_dims;
445 SLang_Array_Type *at;
446 unsigned char type;
447 int dims [SLARRAY_MAX_DIMS];
448 int (*anew) (unsigned char, unsigned int);
449
450 num_dims = (SLang_Num_Function_Args - 1);
451
452 if (-1 == SLang_pop_datatype (&type))
453 return -1;
454
455 anew = (_SLclass_get_class (type))->cl_anew;
456 if (anew != NULL)
457 return (*anew) (type, num_dims);
458
459 if (-1 == pop_array_indices (dims, num_dims))
460 return -1;
461
462 if (NULL == (at = SLang_create_array (type, 0, NULL, dims, num_dims)))
463 return -1;
464
465 return SLang_push_array (at, 1);
466 }
467
push_element_at_addr(SLang_Array_Type * at,VOID_STAR data,int allow_null)468 static int push_element_at_addr (SLang_Array_Type *at,
469 VOID_STAR data, int allow_null)
470 {
471 SLang_Class_Type *cl;
472
473 cl = at->cl;
474 if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
475 && (*(VOID_STAR *) data == NULL))
476 {
477 if (allow_null)
478 return SLang_push_null ();
479
480 SLang_verror (SL_VARIABLE_UNINITIALIZED,
481 "%s array has unitialized element", cl->cl_name);
482 return -1;
483 }
484
485 return (*cl->cl_apush)(at->data_type, data);
486 }
487
coerse_array_to_linear(SLang_Array_Type * at)488 static int coerse_array_to_linear (SLang_Array_Type *at)
489 {
490 SLarray_Range_Array_Type *range;
491 int *data;
492 int xmin, dx;
493 unsigned int i, imax;
494
495 /* FIXME: Priority = low. This assumes that if an array is not linear, then
496 * it is a range.
497 */
498 if (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE))
499 return 0;
500
501 range = (SLarray_Range_Array_Type *) at->data;
502 xmin = range->first_index;
503 dx = range->delta;
504
505 imax = at->num_elements;
506 data = (int *) SLmalloc ((imax + 1) * sizeof (int));
507 if (data == NULL)
508 return -1;
509
510 for (i = 0; i < imax; i++)
511 {
512 data [i] = xmin;
513 xmin += dx;
514 }
515
516 SLfree ((char *) range);
517 at->data = (VOID_STAR) data;
518 at->flags &= ~SLARR_DATA_VALUE_IS_RANGE;
519 at->index_fun = linear_get_data_addr;
520 return 0;
521 }
522
523 static void
free_index_objects(SLang_Object_Type * index_objs,unsigned int num_indices)524 free_index_objects (SLang_Object_Type *index_objs, unsigned int num_indices)
525 {
526 unsigned int i;
527 SLang_Object_Type *obj;
528
529 for (i = 0; i < num_indices; i++)
530 {
531 obj = index_objs + i;
532 if (obj->data_type != 0)
533 SLang_free_object (obj);
534 }
535 }
536
537 static int
pop_indices(SLang_Object_Type * index_objs,unsigned int num_indices,int * is_index_array)538 pop_indices (SLang_Object_Type *index_objs, unsigned int num_indices,
539 int *is_index_array)
540 {
541 unsigned int i;
542
543 SLMEMSET((char *) index_objs, 0, num_indices * sizeof (SLang_Object_Type));
544
545 *is_index_array = 0;
546
547 if (num_indices >= SLARRAY_MAX_DIMS)
548 {
549 SLang_verror (SL_INVALID_PARM, "too many indices for array");
550 return -1;
551 }
552
553 i = num_indices;
554 while (i != 0)
555 {
556 SLang_Object_Type *obj;
557
558 i--;
559 obj = index_objs + i;
560 if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, obj, 1))
561 goto return_error;
562
563 if (obj->data_type == SLANG_ARRAY_TYPE)
564 {
565 SLang_Array_Type *at = obj->v.array_val;
566
567 if (at->num_dims == 1)
568 {
569 if ((num_indices == 1)
570 && (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE)))
571 *is_index_array = 1;
572 }
573 else
574 {
575 SLang_verror (SL_INVALID_PARM, "expecting a 1-d index array");
576 goto return_error;
577 }
578 }
579 }
580
581 return 0;
582
583 return_error:
584 free_index_objects (index_objs, num_indices);
585 return -1;
586 }
587
588 /* Here ind_at is a linear 1-d array of indices */
589 static int
check_index_array_ranges(SLang_Array_Type * at,SLang_Array_Type * ind_at)590 check_index_array_ranges (SLang_Array_Type *at, SLang_Array_Type *ind_at)
591 {
592 int *indices, *indices_max;
593 unsigned int num_elements;
594
595 num_elements = at->num_elements;
596 indices = (int *) ind_at->data;
597 indices_max = indices + ind_at->num_elements;
598
599 while (indices < indices_max)
600 {
601 unsigned int d;
602
603 d = (unsigned int) *indices++;
604 if (d >= num_elements)
605 {
606 SLang_verror (SL_INVALID_PARM,
607 "index-array is out of range");
608 return -1;
609 }
610 }
611 return 0;
612 }
613
614 static int
transfer_n_elements(SLang_Array_Type * at,VOID_STAR dest_data,VOID_STAR src_data,unsigned int sizeof_type,unsigned int n,int is_ptr)615 transfer_n_elements (SLang_Array_Type *at, VOID_STAR dest_data, VOID_STAR src_data,
616 unsigned int sizeof_type, unsigned int n, int is_ptr)
617 {
618 unsigned char data_type;
619 SLang_Class_Type *cl;
620
621 if (is_ptr == 0)
622 {
623 SLMEMCPY ((char *) dest_data, (char *)src_data, n * sizeof_type);
624 return 0;
625 }
626
627 data_type = at->data_type;
628 cl = at->cl;
629
630 while (n != 0)
631 {
632 if (*(VOID_STAR *)dest_data != NULL)
633 {
634 (*cl->cl_destroy) (data_type, dest_data);
635 *(VOID_STAR *) dest_data = NULL;
636 }
637
638 if (*(VOID_STAR *) src_data == NULL)
639 *(VOID_STAR *) dest_data = NULL;
640 else
641 {
642 if (-1 == (*cl->cl_acopy) (data_type, src_data, dest_data))
643 /* No need to destroy anything */
644 return -1;
645 }
646
647 src_data = (VOID_STAR) ((char *)src_data + sizeof_type);
648 dest_data = (VOID_STAR) ((char *)dest_data + sizeof_type);
649
650 n--;
651 }
652
653 return 0;
654 }
655
656 int
_SLarray_aget_transfer_elem(SLang_Array_Type * at,int * indices,VOID_STAR new_data,unsigned int sizeof_type,int is_ptr)657 _SLarray_aget_transfer_elem (SLang_Array_Type *at, int *indices,
658 VOID_STAR new_data, unsigned int sizeof_type, int is_ptr)
659 {
660 VOID_STAR at_data;
661
662 /* Since 1 element is being transferred, there is not need to coerse
663 * the array to linear.
664 */
665 if (NULL == (at_data = get_data_addr (at, indices)))
666 return -1;
667
668 return transfer_n_elements (at, new_data, at_data, sizeof_type, 1, is_ptr);
669 }
670
671 /* Here the ind_at index-array is a 1-d array of indices. This function
672 * creates a 1-d array of made up of values of 'at' at the locations
673 * specified by the indices. The result is pushed.
674 */
675 static int
aget_from_index_array(SLang_Array_Type * at,SLang_Array_Type * ind_at)676 aget_from_index_array (SLang_Array_Type *at,
677 SLang_Array_Type *ind_at)
678 {
679 SLang_Array_Type *new_at;
680 int *indices, *indices_max;
681 unsigned char *new_data, *src_data;
682 unsigned int sizeof_type;
683 int is_ptr;
684
685 if (-1 == coerse_array_to_linear (at))
686 return -1;
687
688 if (-1 == coerse_array_to_linear (ind_at))
689 return -1;
690
691 if (-1 == check_index_array_ranges (at, ind_at))
692 return -1;
693
694 if (NULL == (new_at = SLang_create_array (at->data_type, 0, NULL, ind_at->dims, 1)))
695 return -1;
696
697 /* Since the index array is linear, I can address it directly */
698 indices = (int *) ind_at->data;
699 indices_max = indices + ind_at->num_elements;
700
701 src_data = (unsigned char *) at->data;
702 new_data = (unsigned char *) new_at->data;
703 sizeof_type = new_at->sizeof_type;
704 is_ptr = (new_at->flags & SLARR_DATA_VALUE_IS_POINTER);
705
706 while (indices < indices_max)
707 {
708 unsigned int offset;
709
710 offset = sizeof_type * (unsigned int)*indices;
711 if (-1 == transfer_n_elements (at, (VOID_STAR) new_data,
712 (VOID_STAR) (src_data + offset),
713 sizeof_type, 1, is_ptr))
714 {
715 SLang_free_array (new_at);
716 return -1;
717 }
718
719 new_data += sizeof_type;
720 indices++;
721 }
722
723 return SLang_push_array (new_at, 1);
724 }
725
726 /* This is extremely ugly. It is due to the fact that the index_objects
727 * may contain ranges. This is a utility function for the aget/aput
728 * routines
729 */
730 static int
convert_nasty_index_objs(SLang_Array_Type * at,SLang_Object_Type * index_objs,unsigned int num_indices,int ** index_data,int * range_buf,int * range_delta_buf,int * max_dims,unsigned int * num_elements,int * is_array,int is_dim_array[SLARRAY_MAX_DIMS])731 convert_nasty_index_objs (SLang_Array_Type *at,
732 SLang_Object_Type *index_objs,
733 unsigned int num_indices,
734 int **index_data,
735 int *range_buf, int *range_delta_buf,
736 int *max_dims,
737 unsigned int *num_elements,
738 int *is_array, int is_dim_array[SLARRAY_MAX_DIMS])
739 {
740 unsigned int i, total_num_elements;
741 SLang_Array_Type *ind_at;
742
743 if (num_indices != at->num_dims)
744 {
745 SLang_verror (SL_INVALID_PARM, "Array requires %u indices", at->num_dims);
746 return -1;
747 }
748
749 *is_array = 0;
750 total_num_elements = 1;
751 for (i = 0; i < num_indices; i++)
752 {
753 int max_index, min_index;
754 SLang_Object_Type *obj;
755 int at_dims_i;
756
757 at_dims_i = at->dims[i];
758 obj = index_objs + i;
759 range_delta_buf [i] = 0;
760
761 if (obj->data_type == SLANG_INT_TYPE)
762 {
763 range_buf [i] = min_index = max_index = obj->v.int_val;
764 max_dims [i] = 1;
765 index_data[i] = range_buf + i;
766 is_dim_array[i] = 0;
767 }
768 else
769 {
770 *is_array = 1;
771 is_dim_array[i] = 1;
772 ind_at = obj->v.array_val;
773
774 if (ind_at->flags & SLARR_DATA_VALUE_IS_RANGE)
775 {
776 SLarray_Range_Array_Type *r;
777 int delta;
778 int first_index, last_index;
779
780 r = (SLarray_Range_Array_Type *) ind_at->data;
781
782 /* In an array indexing context, range arrays have different
783 * semantics. Consider a[[0:10]]. Clearly this means elements
784 * 0-10 of a. But what does a[[0:-1]] mean? By itself,
785 * [0:-1] is a null matrix []. But, it is useful in an
786 * indexing context to allow -1 to refer to the last element
787 * of the array. Similarly, [-3:-1] refers to the last 3
788 * elements.
789 *
790 * However, [-1:-3] does not refer to any of the elements.
791 */
792
793 /* FIXME: Priority=High; I think this is broken behavior
794 * and should be rethought. That is, a[[0:-1]] should
795 * specify no elements. That is, the behavior should be:
796 * [0:9] ==> first 9 elements
797 * [-3:-1] ==> last 3 elements
798 * [0:-1] ==> [] (no elements)
799 * [0:-1:-1] ==> [0, -1] ==> first and last elements
800 * [-1:-3] ==> []
801 *
802 * Unfortunately, this is going to be difficult to fix
803 * because of the way rubber ranges are stored:
804 * [*] ==> [0:-1]
805 *
806 * Perhaps it is just best to document this behavior.
807 * Sigh.
808 */
809 if ((first_index = r->first_index) < 0)
810 {
811 if (at_dims_i != 0)
812 first_index = (at_dims_i + first_index) % at_dims_i;
813 }
814
815 if ((last_index = r->last_index) < 0)
816 {
817 if (at_dims_i != 0)
818 last_index = (at_dims_i + last_index) % at_dims_i;
819 }
820
821 delta = r->delta;
822
823 range_delta_buf [i] = delta;
824 range_buf[i] = first_index;
825
826 if (delta > 0)
827 {
828 if (first_index > last_index)
829 max_dims[i] = min_index = max_index = 0;
830 else
831 {
832 max_index = min_index = first_index;
833 while (max_index + delta <= last_index)
834 max_index += delta;
835 max_dims [i] = 1 + (max_index - min_index) / delta;
836 }
837 }
838 else
839 {
840 if (first_index < last_index)
841 max_dims[i] = min_index = max_index = 0;
842 else
843 {
844 min_index = max_index = first_index;
845 while (min_index + delta >= last_index)
846 min_index += delta;
847 max_dims [i] = 1 + (max_index - min_index) / (-delta);
848 }
849 }
850 }
851 else
852 {
853 int *tmp, *tmp_max;
854
855 if (0 == (max_dims[i] = ind_at->num_elements))
856 {
857 total_num_elements = 0;
858 break;
859 }
860
861 tmp = (int *) ind_at->data;
862 tmp_max = tmp + ind_at->num_elements;
863 index_data [i] = tmp;
864
865 min_index = max_index = *tmp;
866 while (tmp < tmp_max)
867 {
868 if (max_index > *tmp)
869 max_index = *tmp;
870 if (min_index < *tmp)
871 min_index = *tmp;
872
873 tmp++;
874 }
875 }
876 }
877
878 if ((at_dims_i == 0) && (max_dims[i] == 0))
879 {
880 total_num_elements = 0;
881 continue;
882 }
883
884 if (max_index < 0)
885 max_index += at_dims_i;
886 if (min_index < 0)
887 min_index += at_dims_i;
888
889 if ((min_index < 0) || (min_index >= at_dims_i)
890 || (max_index < 0) || (max_index >= at_dims_i))
891 {
892 SLang_verror (SL_INVALID_PARM, "Array index %u ([%d:%d]) out of allowed range [0->%d]",
893 i, min_index, max_index, at_dims_i);
894 return -1;
895 }
896
897 total_num_elements = total_num_elements * max_dims[i];
898 }
899
900 *num_elements = total_num_elements;
901 return 0;
902 }
903
904 /* This routine pushes a 1-d vector of values from 'at' indexed by
905 * the objects 'index_objs'. These objects can either be integers or
906 * 1-d integer arrays. The fact that the 1-d arrays can be ranges
907 * makes this look ugly.
908 */
909 static int
aget_from_indices(SLang_Array_Type * at,SLang_Object_Type * index_objs,unsigned int num_indices)910 aget_from_indices (SLang_Array_Type *at,
911 SLang_Object_Type *index_objs, unsigned int num_indices)
912 {
913 int *index_data [SLARRAY_MAX_DIMS];
914 int range_buf [SLARRAY_MAX_DIMS];
915 int range_delta_buf [SLARRAY_MAX_DIMS];
916 int max_dims [SLARRAY_MAX_DIMS];
917 unsigned int i, num_elements;
918 SLang_Array_Type *new_at;
919 int map_indices[SLARRAY_MAX_DIMS];
920 int indices [SLARRAY_MAX_DIMS];
921 unsigned int sizeof_type;
922 int is_ptr, ret, is_array;
923 char *new_data;
924 SLang_Class_Type *cl;
925 int is_dim_array[SLARRAY_MAX_DIMS];
926
927 if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
928 index_data, range_buf, range_delta_buf,
929 max_dims, &num_elements, &is_array,
930 is_dim_array))
931 return -1;
932
933 is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
934 sizeof_type = at->sizeof_type;
935
936 cl = _SLclass_get_class (at->data_type);
937
938 if ((is_array == 0) && (num_elements == 1))
939 {
940 new_data = (char *)cl->cl_transfer_buf;
941 memset (new_data, 0, sizeof_type);
942 new_at = NULL;
943 }
944 else
945 {
946 int i_num_elements = (int)num_elements;
947
948 new_at = SLang_create_array (at->data_type, 0, NULL, &i_num_elements, 1);
949 if (NULL == new_at)
950 return -1;
951 if (num_elements == 0)
952 return SLang_push_array (new_at, 1);
953
954 new_data = (char *)new_at->data;
955 }
956
957 SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
958 do
959 {
960 for (i = 0; i < num_indices; i++)
961 {
962 int j;
963
964 j = map_indices[i];
965
966 if (0 != range_delta_buf[i])
967 indices[i] = range_buf[i] + j * range_delta_buf[i];
968 else
969 indices[i] = index_data [i][j];
970 }
971
972 if (-1 == _SLarray_aget_transfer_elem (at, indices, (VOID_STAR)new_data, sizeof_type, is_ptr))
973 {
974 SLang_free_array (new_at);
975 return -1;
976 }
977 new_data += sizeof_type;
978 }
979 while (0 == next_index (map_indices, max_dims, num_indices));
980
981 if (new_at != NULL)
982 {
983 int num_dims = 0;
984 /* Fixup dimensions on array */
985 for (i = 0; i < num_indices; i++)
986 {
987 if (is_dim_array[i]) /* was: (max_dims[i] > 1) */
988 {
989 new_at->dims[num_dims] = max_dims[i];
990 num_dims++;
991 }
992 }
993
994 if (num_dims != 0) new_at->num_dims = num_dims;
995 return SLang_push_array (new_at, 1);
996 }
997
998 /* Here new_data is a whole new copy, so free it after the push */
999 new_data -= sizeof_type;
1000 if (is_ptr && (*(VOID_STAR *)new_data == NULL))
1001 ret = SLang_push_null ();
1002 else
1003 {
1004 ret = (*cl->cl_apush) (at->data_type, (VOID_STAR)new_data);
1005 (*cl->cl_adestroy) (at->data_type, (VOID_STAR)new_data);
1006 }
1007
1008 return ret;
1009 }
1010
push_string_as_array(unsigned char * s,unsigned int len)1011 static int push_string_as_array (unsigned char *s, unsigned int len)
1012 {
1013 int ilen;
1014 SLang_Array_Type *at;
1015
1016 ilen = (int) len;
1017
1018 at = SLang_create_array (SLANG_UCHAR_TYPE, 0, NULL, &ilen, 1);
1019 if (at == NULL)
1020 return -1;
1021
1022 memcpy ((char *)at->data, (char *)s, len);
1023 return SLang_push_array (at, 1);
1024 }
1025
pop_array_as_string(char ** sp)1026 static int pop_array_as_string (char **sp)
1027 {
1028 SLang_Array_Type *at;
1029 int ret;
1030
1031 *sp = NULL;
1032
1033 if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
1034 return -1;
1035
1036 ret = 0;
1037
1038 if (NULL == (*sp = SLang_create_nslstring ((char *) at->data, at->num_elements)))
1039 ret = -1;
1040
1041 SLang_free_array (at);
1042 return ret;
1043 }
1044
pop_array_as_bstring(SLang_BString_Type ** bs)1045 static int pop_array_as_bstring (SLang_BString_Type **bs)
1046 {
1047 SLang_Array_Type *at;
1048 int ret;
1049
1050 *bs = NULL;
1051
1052 if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
1053 return -1;
1054
1055 ret = 0;
1056
1057 if (NULL == (*bs = SLbstring_create ((unsigned char *) at->data, at->num_elements)))
1058 ret = -1;
1059
1060 SLang_free_array (at);
1061 return ret;
1062 }
1063
aget_from_array(unsigned int num_indices)1064 static int aget_from_array (unsigned int num_indices)
1065 {
1066 SLang_Array_Type *at;
1067 SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
1068 int ret;
1069 int is_index_array;
1070 unsigned int i;
1071
1072 if (num_indices > SLARRAY_MAX_DIMS)
1073 {
1074 SLang_verror (SL_INVALID_PARM, "Number of dims must be less than %d", SLARRAY_MAX_DIMS);
1075 return -1;
1076 }
1077
1078 if (-1 == pop_array (&at, 1))
1079 return -1;
1080
1081 if (-1 == pop_indices (index_objs, num_indices, &is_index_array))
1082 {
1083 SLang_free_array (at);
1084 return -1;
1085 }
1086
1087 if (is_index_array == 0)
1088 ret = aget_from_indices (at, index_objs, num_indices);
1089 else
1090 ret = aget_from_index_array (at, index_objs[0].v.array_val);
1091
1092 SLang_free_array (at);
1093 for (i = 0; i < num_indices; i++)
1094 SLang_free_object (index_objs + i);
1095
1096 return ret;
1097 }
1098
push_string_element(unsigned char type,unsigned char * s,unsigned int len)1099 static int push_string_element (unsigned char type, unsigned char *s, unsigned int len)
1100 {
1101 int i;
1102
1103 if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
1104 {
1105 char *str;
1106
1107 /* The indices are array values. So, do this: */
1108 if (-1 == push_string_as_array (s, len))
1109 return -1;
1110
1111 if (-1 == aget_from_array (1))
1112 return -1;
1113
1114 if (type == SLANG_BSTRING_TYPE)
1115 {
1116 SLang_BString_Type *bs;
1117 int ret;
1118
1119 if (-1 == pop_array_as_bstring (&bs))
1120 return -1;
1121
1122 ret = SLang_push_bstring (bs);
1123 SLbstring_free (bs);
1124 return ret;
1125 }
1126
1127 if (-1 == pop_array_as_string (&str))
1128 return -1;
1129 return _SLang_push_slstring (str); /* frees s upon error */
1130 }
1131
1132 if (-1 == SLang_pop_integer (&i))
1133 return -1;
1134
1135 if (i < 0) i = i + (int)len;
1136 if ((unsigned int) i > len)
1137 i = len; /* get \0 character --- bstrings include it as well */
1138
1139 i = s[(unsigned int) i];
1140
1141 return SLang_push_integer (i);
1142 }
1143
1144 /* ARRAY[i, j, k] generates code: __args i j ...k ARRAY __aput/__aget
1145 * Here i, j, ... k may be a mixture of integers and 1-d arrays, or
1146 * a single 2-d array of indices. The 2-d index array is generated by the
1147 * 'where' function.
1148 *
1149 * If ARRAY is of type DataType, then this function will create an array of
1150 * the appropriate type. In that case, the indices i, j, ..., k must be
1151 * integers.
1152 */
_SLarray_aget(void)1153 int _SLarray_aget (void)
1154 {
1155 unsigned int num_indices;
1156 int type;
1157 int (*aget_fun) (unsigned char, unsigned int);
1158
1159 num_indices = (SLang_Num_Function_Args - 1);
1160
1161 type = SLang_peek_at_stack ();
1162 switch (type)
1163 {
1164 case -1:
1165 return -1; /* stack underflow */
1166
1167 case SLANG_DATATYPE_TYPE:
1168 return push_create_new_array ();
1169
1170 case SLANG_BSTRING_TYPE:
1171 if (1 == num_indices)
1172 {
1173 SLang_BString_Type *bs;
1174 int ret;
1175 unsigned int len;
1176 unsigned char *s;
1177
1178 if (-1 == SLang_pop_bstring (&bs))
1179 return -1;
1180
1181 if (NULL == (s = SLbstring_get_pointer (bs, &len)))
1182 ret = -1;
1183 else
1184 ret = push_string_element (type, s, len);
1185
1186 SLbstring_free (bs);
1187 return ret;
1188 }
1189 break;
1190
1191 case SLANG_STRING_TYPE:
1192 if (1 == num_indices)
1193 {
1194 char *s;
1195 int ret;
1196
1197 if (-1 == SLang_pop_slstring (&s))
1198 return -1;
1199
1200 ret = push_string_element (type, (unsigned char *)s, strlen (s));
1201 SLang_free_slstring (s);
1202 return ret;
1203 }
1204 break;
1205
1206 case SLANG_ARRAY_TYPE:
1207 break;
1208
1209 default:
1210 aget_fun = _SLclass_get_class (type)->cl_aget;
1211 if (NULL != aget_fun)
1212 return (*aget_fun) (type, num_indices);
1213 }
1214
1215 return aget_from_array (num_indices);
1216 }
1217
1218 int
_SLarray_aput_transfer_elem(SLang_Array_Type * at,int * indices,VOID_STAR data_to_put,unsigned int sizeof_type,int is_ptr)1219 _SLarray_aput_transfer_elem (SLang_Array_Type *at, int *indices,
1220 VOID_STAR data_to_put, unsigned int sizeof_type, int is_ptr)
1221 {
1222 VOID_STAR at_data;
1223
1224 /* Since 1 element is being transferred, there is no need to coerse
1225 * the array to linear.
1226 */
1227 if (NULL == (at_data = get_data_addr (at, indices)))
1228 return -1;
1229
1230 return transfer_n_elements (at, at_data, data_to_put, sizeof_type, 1, is_ptr);
1231 }
1232
1233 static int
aput_get_array_to_put(SLang_Class_Type * cl,unsigned int num_elements,int allow_array,SLang_Array_Type ** at_ptr,char ** data_to_put,unsigned int * data_increment)1234 aput_get_array_to_put (SLang_Class_Type *cl, unsigned int num_elements, int allow_array,
1235 SLang_Array_Type **at_ptr, char **data_to_put, unsigned int *data_increment)
1236 {
1237 unsigned char data_type;
1238 SLang_Array_Type *at;
1239
1240 *at_ptr = NULL;
1241
1242 data_type = cl->cl_data_type;
1243 if (-1 == SLclass_typecast (data_type, 1, allow_array))
1244 return -1;
1245
1246 if ((data_type != SLANG_ARRAY_TYPE)
1247 && (data_type != SLANG_ANY_TYPE)
1248 && (SLANG_ARRAY_TYPE == SLang_peek_at_stack ()))
1249 {
1250 if (-1 == SLang_pop_array (&at, 0))
1251 return -1;
1252
1253 if ((at->num_elements != num_elements)
1254 #if 0
1255 || (at->num_dims != 1)
1256 #endif
1257 )
1258 {
1259 SLang_verror (SL_TYPE_MISMATCH, "Array size is inappropriate for use with index-array");
1260 SLang_free_array (at);
1261 return -1;
1262 }
1263
1264 *data_to_put = (char *) at->data;
1265 *data_increment = at->sizeof_type;
1266 *at_ptr = at;
1267 return 0;
1268 }
1269
1270 *data_increment = 0;
1271 *data_to_put = (char *) cl->cl_transfer_buf;
1272
1273 if (-1 == (*cl->cl_apop)(data_type, (VOID_STAR) *data_to_put))
1274 return -1;
1275
1276 return 0;
1277 }
1278
1279 static int
aput_from_indices(SLang_Array_Type * at,SLang_Object_Type * index_objs,unsigned int num_indices)1280 aput_from_indices (SLang_Array_Type *at,
1281 SLang_Object_Type *index_objs, unsigned int num_indices)
1282 {
1283 int *index_data [SLARRAY_MAX_DIMS];
1284 int range_buf [SLARRAY_MAX_DIMS];
1285 int range_delta_buf [SLARRAY_MAX_DIMS];
1286 int max_dims [SLARRAY_MAX_DIMS];
1287 unsigned int i, num_elements;
1288 SLang_Array_Type *bt;
1289 int map_indices[SLARRAY_MAX_DIMS];
1290 int indices [SLARRAY_MAX_DIMS];
1291 unsigned int sizeof_type;
1292 int is_ptr, is_array, ret;
1293 char *data_to_put;
1294 unsigned int data_increment;
1295 SLang_Class_Type *cl;
1296 int is_dim_array [SLARRAY_MAX_DIMS];
1297
1298 if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
1299 index_data, range_buf, range_delta_buf,
1300 max_dims, &num_elements, &is_array,
1301 is_dim_array))
1302 return -1;
1303
1304 cl = at->cl;
1305
1306 if (-1 == aput_get_array_to_put (cl, num_elements, is_array,
1307 &bt, &data_to_put, &data_increment))
1308 return -1;
1309
1310 sizeof_type = at->sizeof_type;
1311 is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
1312
1313 ret = -1;
1314
1315 SLMEMSET((char *) map_indices, 0, sizeof(map_indices));
1316 if (num_elements) do
1317 {
1318 for (i = 0; i < num_indices; i++)
1319 {
1320 int j;
1321
1322 j = map_indices[i];
1323
1324 if (0 != range_delta_buf[i])
1325 indices[i] = range_buf[i] + j * range_delta_buf[i];
1326 else
1327 indices[i] = index_data [i][j];
1328 }
1329
1330 if (-1 == _SLarray_aput_transfer_elem (at, indices, (VOID_STAR)data_to_put, sizeof_type, is_ptr))
1331 goto return_error;
1332
1333 data_to_put += data_increment;
1334 }
1335 while (0 == next_index (map_indices, max_dims, num_indices));
1336
1337 ret = 0;
1338
1339 /* drop */
1340
1341 return_error:
1342 if (bt == NULL)
1343 {
1344 if (is_ptr)
1345 (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR) data_to_put);
1346 }
1347 else SLang_free_array (bt);
1348
1349 return ret;
1350 }
1351
1352 static int
aput_from_index_array(SLang_Array_Type * at,SLang_Array_Type * ind_at)1353 aput_from_index_array (SLang_Array_Type *at, SLang_Array_Type *ind_at)
1354 {
1355 int *indices, *indices_max;
1356 unsigned int sizeof_type;
1357 char *data_to_put, *dest_data;
1358 unsigned int data_increment;
1359 int is_ptr;
1360 SLang_Array_Type *bt;
1361 SLang_Class_Type *cl;
1362 int ret;
1363
1364 if (-1 == coerse_array_to_linear (at))
1365 return -1;
1366
1367 if (-1 == coerse_array_to_linear (ind_at))
1368 return -1;
1369
1370 if (-1 == check_index_array_ranges (at, ind_at))
1371 return -1;
1372
1373 sizeof_type = at->sizeof_type;
1374
1375 cl = at->cl;
1376
1377 /* Note that if bt is returned as non NULL, then the array is a linear
1378 * one.
1379 */
1380 if (-1 == aput_get_array_to_put (cl, ind_at->num_elements, 1,
1381 &bt, &data_to_put, &data_increment))
1382 return -1;
1383
1384 /* Since the index array is linear, I can address it directly */
1385 indices = (int *) ind_at->data;
1386 indices_max = indices + ind_at->num_elements;
1387
1388 is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
1389 dest_data = (char *) at->data;
1390
1391 ret = -1;
1392 while (indices < indices_max)
1393 {
1394 unsigned int offset;
1395
1396 offset = sizeof_type * (unsigned int)*indices;
1397
1398 if (-1 == transfer_n_elements (at, (VOID_STAR) (dest_data + offset),
1399 (VOID_STAR) data_to_put, sizeof_type, 1,
1400 is_ptr))
1401 goto return_error;
1402
1403 indices++;
1404 data_to_put += data_increment;
1405 }
1406
1407 ret = 0;
1408 /* Drop */
1409
1410 return_error:
1411
1412 if (bt == NULL)
1413 {
1414 if (is_ptr)
1415 (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR)data_to_put);
1416 }
1417 else SLang_free_array (bt);
1418
1419 return ret;
1420 }
1421
1422 /* ARRAY[i, j, k] = generates code: __args i j k ARRAY __aput
1423 */
_SLarray_aput(void)1424 int _SLarray_aput (void)
1425 {
1426 unsigned int num_indices;
1427 SLang_Array_Type *at;
1428 SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
1429 int ret;
1430 int is_index_array;
1431 int (*aput_fun) (unsigned char, unsigned int);
1432 int type;
1433
1434 ret = -1;
1435 num_indices = (SLang_Num_Function_Args - 1);
1436
1437 type = SLang_peek_at_stack ();
1438 switch (type)
1439 {
1440 case -1:
1441 return -1;
1442
1443 case SLANG_ARRAY_TYPE:
1444 break;
1445
1446 default:
1447 if (NULL != (aput_fun = _SLclass_get_class (type)->cl_aput))
1448 return (*aput_fun) (type, num_indices);
1449 break;
1450 }
1451
1452 if (-1 == SLang_pop_array (&at, 0))
1453 return -1;
1454
1455 if (at->flags & SLARR_DATA_VALUE_IS_READ_ONLY)
1456 {
1457 SLang_verror (SL_READONLY_ERROR, "%s Array is read-only",
1458 SLclass_get_datatype_name (at->data_type));
1459 SLang_free_array (at);
1460 return -1;
1461 }
1462
1463 if (-1 == pop_indices (index_objs, num_indices, &is_index_array))
1464 {
1465 SLang_free_array (at);
1466 return -1;
1467 }
1468
1469 if (is_index_array == 0)
1470 ret = aput_from_indices (at, index_objs, num_indices);
1471 else
1472 ret = aput_from_index_array (at, index_objs[0].v.array_val);
1473
1474 SLang_free_array (at);
1475 free_index_objects (index_objs, num_indices);
1476 return ret;
1477 }
1478
1479 /* This is for 1-d matrices only. It is used by the sort function */
push_element_at_index(SLang_Array_Type * at,int indx)1480 static int push_element_at_index (SLang_Array_Type *at, int indx)
1481 {
1482 VOID_STAR data;
1483
1484 if (NULL == (data = get_data_addr (at, &indx)))
1485 return -1;
1486
1487 return push_element_at_addr (at, (VOID_STAR) data, 1);
1488 }
1489
1490 static SLang_Name_Type *Sort_Function;
1491 static SLang_Array_Type *Sort_Array;
1492
sort_cmp_fun(int * a,int * b)1493 static int sort_cmp_fun (int *a, int *b)
1494 {
1495 int cmp;
1496
1497 if (SLang_Error
1498 || (-1 == push_element_at_index (Sort_Array, *a))
1499 || (-1 == push_element_at_index (Sort_Array, *b))
1500 || (-1 == SLexecute_function (Sort_Function))
1501 || (-1 == SLang_pop_integer (&cmp)))
1502 {
1503 /* DO not allow qsort to loop forever. Return something meaningful */
1504 if (*a > *b) return 1;
1505 if (*a < *b) return -1;
1506 return 0;
1507 }
1508
1509 return cmp;
1510 }
1511
builtin_sort_cmp_fun(int * a,int * b)1512 static int builtin_sort_cmp_fun (int *a, int *b)
1513 {
1514 VOID_STAR a_data;
1515 VOID_STAR b_data;
1516 SLang_Class_Type *cl;
1517
1518 cl = Sort_Array->cl;
1519
1520 if ((SLang_Error == 0)
1521 && (NULL != (a_data = get_data_addr (Sort_Array, a)))
1522 && (NULL != (b_data = get_data_addr (Sort_Array, b))))
1523 {
1524 int cmp;
1525
1526 if ((Sort_Array->flags & SLARR_DATA_VALUE_IS_POINTER)
1527 && ((*(VOID_STAR *) a_data == NULL) || (*(VOID_STAR *) a_data == NULL)))
1528 {
1529 SLang_verror (SL_VARIABLE_UNINITIALIZED,
1530 "%s array has unitialized element", cl->cl_name);
1531 }
1532 else if (0 == (*cl->cl_cmp)(Sort_Array->data_type, a_data, b_data, &cmp))
1533 return cmp;
1534 }
1535
1536
1537 if (*a > *b) return 1;
1538 if (*a == *b) return 0;
1539 return -1;
1540 }
1541
sort_array_internal(SLang_Array_Type * at_str,SLang_Name_Type * entry,int (* sort_fun)(int *,int *))1542 static void sort_array_internal (SLang_Array_Type *at_str,
1543 SLang_Name_Type *entry,
1544 int (*sort_fun)(int *, int *))
1545 {
1546 SLang_Array_Type *ind_at;
1547 /* This is a silly hack to make up for braindead compilers and the lack of
1548 * uniformity in prototypes for qsort.
1549 */
1550 void (*qsort_fun) (char *, unsigned int, int, int (*)(int *, int *));
1551 int *indx;
1552 int i, n;
1553 int dims[1];
1554
1555 if (Sort_Array != NULL)
1556 {
1557 SLang_verror (SL_NOT_IMPLEMENTED, "array_sort is not recursive");
1558 return;
1559 }
1560
1561 n = at_str->num_elements;
1562
1563 if (at_str->num_dims != 1)
1564 {
1565 SLang_verror (SL_INVALID_PARM, "sort is restricted to 1 dim arrays");
1566 return;
1567 }
1568
1569 dims [0] = n;
1570
1571 if (NULL == (ind_at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 1)))
1572 return;
1573
1574 indx = (int *) ind_at->data;
1575 for (i = 0; i < n; i++) indx[i] = i;
1576
1577 if (n > 1)
1578 {
1579 qsort_fun = (void (*)(char *, unsigned int, int, int (*)(int *,
1580 int *)))
1581 qsort;
1582
1583 Sort_Array = at_str;
1584 Sort_Function = entry;
1585 (*qsort_fun) ((char *) indx, n, sizeof (int), sort_fun);
1586 }
1587
1588 Sort_Array = NULL;
1589 (void) SLang_push_array (ind_at, 1);
1590 }
1591
sort_array(void)1592 static void sort_array (void)
1593 {
1594 SLang_Name_Type *entry;
1595 SLang_Array_Type *at;
1596 int (*sort_fun) (int *, int *);
1597
1598 if (SLang_Num_Function_Args != 1)
1599 {
1600 sort_fun = sort_cmp_fun;
1601
1602 if (NULL == (entry = SLang_pop_function ()))
1603 return;
1604
1605 if (-1 == SLang_pop_array (&at, 1))
1606 return;
1607 }
1608 else
1609 {
1610 sort_fun = builtin_sort_cmp_fun;
1611 if (-1 == SLang_pop_array (&at, 1))
1612 return;
1613 if (at->cl->cl_cmp == NULL)
1614 {
1615 SLang_verror (SL_NOT_IMPLEMENTED,
1616 "%s does not have a predefined sorting method",
1617 at->cl->cl_name);
1618 SLang_free_array (at);
1619 return;
1620 }
1621 entry = NULL;
1622 }
1623
1624 sort_array_internal (at, entry, sort_fun);
1625 SLang_free_array (at);
1626 SLang_free_function (entry);
1627 }
1628
bstring_to_array(SLang_BString_Type * bs)1629 static void bstring_to_array (SLang_BString_Type *bs)
1630 {
1631 unsigned char *s;
1632 unsigned int len;
1633
1634 if (NULL == (s = SLbstring_get_pointer (bs, &len)))
1635 (void) SLang_push_null ();
1636 else
1637 (void) push_string_as_array (s, len);
1638 }
1639
array_to_bstring(SLang_Array_Type * at)1640 static void array_to_bstring (SLang_Array_Type *at)
1641 {
1642 unsigned int nbytes;
1643 SLang_BString_Type *bs;
1644
1645 nbytes = at->num_elements * at->sizeof_type;
1646 bs = SLbstring_create ((unsigned char *)at->data, nbytes);
1647 (void) SLang_push_bstring (bs);
1648 SLbstring_free (bs);
1649 }
1650
init_char_array(void)1651 static void init_char_array (void)
1652 {
1653 SLang_Array_Type *at;
1654 char *s;
1655 unsigned int n, ndim;
1656
1657 if (SLang_pop_slstring (&s)) return;
1658
1659 if (-1 == SLang_pop_array (&at, 0))
1660 goto free_and_return;
1661
1662 if (at->data_type != SLANG_CHAR_TYPE)
1663 {
1664 SLang_doerror("Operation requires character array");
1665 goto free_and_return;
1666 }
1667
1668 n = strlen (s);
1669 ndim = at->num_elements;
1670 if (n > ndim)
1671 {
1672 SLang_doerror("String too big to init array");
1673 goto free_and_return;
1674 }
1675
1676 strncpy((char *) at->data, s, ndim);
1677 /* drop */
1678
1679 free_and_return:
1680 SLang_free_array (at);
1681 SLang_free_slstring (s);
1682 }
1683
array_info(void)1684 static void array_info (void)
1685 {
1686 SLang_Array_Type *at, *bt;
1687 int num_dims;
1688
1689 if (-1 == pop_array (&at, 1))
1690 return;
1691
1692 num_dims = (int)at->num_dims;
1693
1694 if (NULL != (bt = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &num_dims, 1)))
1695 {
1696 int *bdata;
1697 int i;
1698 int *a_dims;
1699
1700 a_dims = at->dims;
1701 bdata = (int *) bt->data;
1702 for (i = 0; i < num_dims; i++) bdata [i] = a_dims [i];
1703
1704 if (0 == SLang_push_array (bt, 1))
1705 {
1706 (void) SLang_push_integer ((int) at->num_dims);
1707 (void) SLang_push_datatype (at->data_type);
1708 }
1709 }
1710
1711 SLang_free_array (at);
1712 }
1713
range_get_data_addr(SLang_Array_Type * at,int * dims)1714 static VOID_STAR range_get_data_addr (SLang_Array_Type *at, int *dims)
1715 {
1716 static int value;
1717 SLarray_Range_Array_Type *r;
1718 int d;
1719
1720 d = *dims;
1721 r = (SLarray_Range_Array_Type *)at->data;
1722
1723 if (d < 0)
1724 d += at->dims[0];
1725
1726 value = r->first_index + d * r->delta;
1727 return (VOID_STAR) &value;
1728 }
1729
inline_implicit_int_array(int * xminptr,int * xmaxptr,int * dxptr)1730 static SLang_Array_Type *inline_implicit_int_array (int *xminptr, int *xmaxptr, int *dxptr)
1731 {
1732 int delta;
1733 SLang_Array_Type *at;
1734 int dims, idims;
1735 SLarray_Range_Array_Type *data;
1736
1737 if (dxptr == NULL) delta = 1;
1738 else delta = *dxptr;
1739
1740 if (delta == 0)
1741 {
1742 SLang_verror (SL_INVALID_PARM, "range-array increment must be non-zero");
1743 return NULL;
1744 }
1745
1746 data = (SLarray_Range_Array_Type *) SLmalloc (sizeof (SLarray_Range_Array_Type));
1747 if (data == NULL)
1748 return NULL;
1749
1750 SLMEMSET((char *) data, 0, sizeof (SLarray_Range_Array_Type));
1751 data->delta = delta;
1752 dims = 0;
1753
1754 if (xminptr != NULL)
1755 data->first_index = *xminptr;
1756 else
1757 data->first_index = 0;
1758
1759 if (xmaxptr != NULL)
1760 data->last_index = *xmaxptr;
1761 else
1762 data->last_index = -1;
1763
1764 /* if ((xminptr != NULL) && (xmaxptr != NULL))
1765 { */
1766 idims = 1 + (data->last_index - data->first_index) / delta;
1767 if (idims > 0)
1768 dims = idims;
1769 /* } */
1770
1771 if (NULL == (at = SLang_create_array (SLANG_INT_TYPE, 0, (VOID_STAR) data, &dims, 1)))
1772 return NULL;
1773
1774 at->index_fun = range_get_data_addr;
1775 at->flags |= SLARR_DATA_VALUE_IS_RANGE;
1776
1777 return at;
1778 }
1779
1780 #if SLANG_HAS_FLOAT
inline_implicit_floating_array(unsigned char type,double * xminptr,double * xmaxptr,double * dxptr)1781 static SLang_Array_Type *inline_implicit_floating_array (unsigned char type,
1782 double *xminptr, double *xmaxptr, double *dxptr)
1783 {
1784 int n, i;
1785 SLang_Array_Type *at;
1786 int dims;
1787 double xmin, xmax, dx;
1788
1789 if ((xminptr == NULL) || (xmaxptr == NULL))
1790 {
1791 SLang_verror (SL_INVALID_PARM, "range-array has unknown size");
1792 return NULL;
1793 }
1794 xmin = *xminptr;
1795 xmax = *xmaxptr;
1796 if (dxptr == NULL) dx = 1.0;
1797 else dx = *dxptr;
1798
1799 if (dx == 0.0)
1800 {
1801 SLang_doerror ("range-array increment must be non-zero");
1802 return NULL;
1803 }
1804
1805 /* I have convinced myself that it is better to use semi-open intervals
1806 * because of less ambiguities. So, [a:b:c] will represent the set of
1807 * values a, a + c, a + 2c ... a + nc
1808 * such that a + nc < b. That is, b lies outside the interval.
1809 */
1810
1811 /* Allow for roundoff by adding 0.5 before truncation */
1812 n = (int)(1.5 + ((xmax - xmin) / dx));
1813 if (n <= 0)
1814 n = 0;
1815 else
1816 {
1817 double last = xmin + (n-1) * dx;
1818
1819 if (dx > 0.0)
1820 {
1821 if (last >= xmax)
1822 n -= 1;
1823 }
1824 else if (last <= xmax)
1825 n -= 1;
1826 }
1827
1828 dims = n;
1829 if (NULL == (at = SLang_create_array1 (type, 0, NULL, &dims, 1, 1)))
1830 return NULL;
1831
1832 if (type == SLANG_DOUBLE_TYPE)
1833 {
1834 double *ptr;
1835
1836 ptr = (double *) at->data;
1837
1838 for (i = 0; i < n; i++)
1839 ptr[i] = xmin + i * dx;
1840 }
1841 else
1842 {
1843 float *ptr;
1844
1845 ptr = (float *) at->data;
1846
1847 for (i = 0; i < n; i++)
1848 ptr[i] = (float) (xmin + i * dx);
1849 }
1850 return at;
1851 }
1852 #endif
1853
1854 /* FIXME: Priority=medium
1855 * This needs to be updated to work with all integer types.
1856 */
_SLarray_inline_implicit_array(void)1857 int _SLarray_inline_implicit_array (void)
1858 {
1859 int int_vals[3];
1860 #if SLANG_HAS_FLOAT
1861 double double_vals[3];
1862 #endif
1863 int has_vals[3];
1864 unsigned int i, count;
1865 SLang_Array_Type *at;
1866 int precedence;
1867 unsigned char type;
1868 int is_int;
1869
1870 count = SLang_Num_Function_Args;
1871
1872 if (count == 2)
1873 has_vals [2] = 0;
1874 else if (count != 3)
1875 {
1876 SLang_doerror ("wrong number of arguments to __implicit_inline_array");
1877 return -1;
1878 }
1879
1880 #if SLANG_HAS_FLOAT
1881 is_int = 1;
1882 #endif
1883
1884 type = 0;
1885 precedence = 0;
1886
1887 i = count;
1888 while (i--)
1889 {
1890 int this_type, this_precedence;
1891
1892 if (-1 == (this_type = SLang_peek_at_stack ()))
1893 return -1;
1894
1895 this_precedence = _SLarith_get_precedence ((unsigned char) this_type);
1896 if (precedence < this_precedence)
1897 {
1898 type = (unsigned char) this_type;
1899 precedence = this_precedence;
1900 }
1901
1902 has_vals [i] = 1;
1903
1904 switch (this_type)
1905 {
1906 case SLANG_NULL_TYPE:
1907 has_vals[i] = 0;
1908 (void) SLdo_pop ();
1909 break;
1910
1911 #if SLANG_HAS_FLOAT
1912 case SLANG_DOUBLE_TYPE:
1913 case SLANG_FLOAT_TYPE:
1914 if (-1 == SLang_pop_double (double_vals + i, NULL, NULL))
1915 return -1;
1916 is_int = 0;
1917 break;
1918 #endif
1919 default:
1920 if (-1 == SLang_pop_integer (int_vals + i))
1921 return -1;
1922 double_vals[i] = (double) int_vals[i];
1923 }
1924 }
1925
1926 #if SLANG_HAS_FLOAT
1927 if (is_int == 0)
1928 at = inline_implicit_floating_array (type,
1929 (has_vals[0] ? &double_vals[0] : NULL),
1930 (has_vals[1] ? &double_vals[1] : NULL),
1931 (has_vals[2] ? &double_vals[2] : NULL));
1932 else
1933 #endif
1934 at = inline_implicit_int_array ((has_vals[0] ? &int_vals[0] : NULL),
1935 (has_vals[1] ? &int_vals[1] : NULL),
1936 (has_vals[2] ? &int_vals[2] : NULL));
1937
1938 if (at == NULL)
1939 return -1;
1940
1941 return SLang_push_array (at, 1);
1942 }
1943
_SLarray_wildcard_array(void)1944 int _SLarray_wildcard_array (void)
1945 {
1946 SLang_Array_Type *at;
1947
1948 if (NULL == (at = inline_implicit_int_array (NULL, NULL, NULL)))
1949 return -1;
1950
1951 return SLang_push_array (at, 1);
1952 }
1953
concat_arrays(unsigned int count)1954 static SLang_Array_Type *concat_arrays (unsigned int count)
1955 {
1956 SLang_Array_Type **arrays;
1957 SLang_Array_Type *at, *bt;
1958 unsigned int i;
1959 int num_elements;
1960 unsigned char type;
1961 char *src_data, *dest_data;
1962 int is_ptr;
1963 unsigned int sizeof_type;
1964 int max_dims, min_dims, max_rows, min_rows;
1965
1966 arrays = (SLang_Array_Type **)SLmalloc (count * sizeof (SLang_Array_Type *));
1967 if (arrays == NULL)
1968 {
1969 SLdo_pop_n (count);
1970 return NULL;
1971 }
1972 SLMEMSET((char *) arrays, 0, count * sizeof(SLang_Array_Type *));
1973
1974 at = NULL;
1975
1976 num_elements = 0;
1977 i = count;
1978
1979 while (i != 0)
1980 {
1981 i--;
1982
1983 if (-1 == SLang_pop_array (&bt, 1))
1984 goto free_and_return;
1985
1986 arrays[i] = bt;
1987 num_elements += (int)bt->num_elements;
1988 }
1989
1990 type = arrays[0]->data_type;
1991 max_dims = min_dims = arrays[0]->num_dims;
1992 min_rows = max_rows = arrays[0]->dims[0];
1993
1994 for (i = 1; i < count; i++)
1995 {
1996 SLang_Array_Type *ct;
1997 int num;
1998
1999 bt = arrays[i];
2000
2001 num = bt->num_dims;
2002 if (num > max_dims) max_dims = num;
2003 if (num < min_dims) min_dims = num;
2004
2005 num = bt->dims[0];
2006 if (num > max_rows) max_rows = num;
2007 if (num < min_rows) min_rows = num;
2008
2009 if (type == bt->data_type)
2010 continue;
2011
2012 if (1 != _SLarray_typecast (bt->data_type, (VOID_STAR) &bt, 1,
2013 type, (VOID_STAR) &ct, 1))
2014 goto free_and_return;
2015
2016 SLang_free_array (bt);
2017 arrays [i] = ct;
2018 }
2019
2020 if (NULL == (at = SLang_create_array (type, 0, NULL, &num_elements, 1)))
2021 goto free_and_return;
2022
2023 is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
2024 sizeof_type = at->sizeof_type;
2025 dest_data = (char *) at->data;
2026
2027 for (i = 0; i < count; i++)
2028 {
2029 bt = arrays[i];
2030
2031 src_data = (char *) bt->data;
2032 num_elements = bt->num_elements;
2033
2034 if (-1 == transfer_n_elements (bt, (VOID_STAR)dest_data, (VOID_STAR)src_data, sizeof_type,
2035 num_elements, is_ptr))
2036 {
2037 SLang_free_array (at);
2038 at = NULL;
2039 goto free_and_return;
2040 }
2041
2042 dest_data += num_elements * sizeof_type;
2043 }
2044
2045 /* If the arrays are all 1-d, and all the same size, then reshape to a
2046 * 2-d array. This will allow us to do, e.g.
2047 * a = [[1,2], [3,4]]
2048 * to specifiy a 2-d.
2049 * Someday I will generalize this.
2050 */
2051 if ((max_dims == min_dims) && (max_dims == 1) && (min_rows == max_rows))
2052 {
2053 at->num_dims = 2;
2054 at->dims[0] = count;
2055 at->dims[1] = min_rows;
2056 }
2057
2058 free_and_return:
2059
2060 for (i = 0; i < count; i++)
2061 SLang_free_array (arrays[i]);
2062 SLfree ((char *) arrays);
2063
2064 return at;
2065 }
2066
_SLarray_inline_array(void)2067 int _SLarray_inline_array (void)
2068 {
2069 SLang_Object_Type *obj;
2070 unsigned char type, this_type;
2071 unsigned int count;
2072 SLang_Array_Type *at;
2073
2074 obj = _SLStack_Pointer;
2075
2076 count = SLang_Num_Function_Args;
2077 type = 0;
2078
2079 while ((count > 0) && (--obj >= _SLRun_Stack))
2080 {
2081 this_type = obj->data_type;
2082
2083 if (type == 0)
2084 type = this_type;
2085
2086 if ((type == this_type) || (type == SLANG_ARRAY_TYPE))
2087 {
2088 count--;
2089 continue;
2090 }
2091
2092 switch (this_type)
2093 {
2094 case SLANG_ARRAY_TYPE:
2095 type = SLANG_ARRAY_TYPE;
2096 break;
2097
2098 case SLANG_COMPLEX_TYPE:
2099 if (0 == _SLarith_Is_Arith_Type[type])
2100 goto type_mismatch;
2101
2102 type = this_type;
2103 break;
2104
2105 default:
2106 if (0 == _SLarith_Is_Arith_Type[this_type])
2107 goto type_mismatch;
2108
2109 if (type == SLANG_COMPLEX_TYPE)
2110 break;
2111
2112 if (0 == _SLarith_Is_Arith_Type[type])
2113 goto type_mismatch;
2114
2115 if (_SLarith_get_precedence (this_type) > _SLarith_get_precedence (type))
2116 type = this_type;
2117 break;
2118 }
2119 count--;
2120 }
2121
2122 if (count != 0)
2123 {
2124 SLang_Error = SL_STACK_UNDERFLOW;
2125 return -1;
2126 }
2127
2128 count = SLang_Num_Function_Args;
2129
2130 if (count == 0)
2131 {
2132 SLang_verror (SL_NOT_IMPLEMENTED, "Empty inline-arrays not supported");
2133 return -1;
2134 }
2135
2136 if (type == SLANG_ARRAY_TYPE)
2137 {
2138 if (NULL == (at = concat_arrays (count)))
2139 return -1;
2140 }
2141 else
2142 {
2143 SLang_Object_Type index_obj;
2144 int icount = (int) count;
2145
2146 if (NULL == (at = SLang_create_array (type, 0, NULL, &icount, 1)))
2147 return -1;
2148
2149 index_obj.data_type = SLANG_INT_TYPE;
2150 while (count != 0)
2151 {
2152 count--;
2153 index_obj.v.int_val = (int) count;
2154 if (-1 == aput_from_indices (at, &index_obj, 1))
2155 {
2156 SLang_free_array (at);
2157 SLdo_pop_n (count);
2158 return -1;
2159 }
2160 }
2161 }
2162
2163 return SLang_push_array (at, 1);
2164
2165 type_mismatch:
2166 _SLclass_type_mismatch_error (type, this_type);
2167 return -1;
2168 }
2169
array_binary_op_result(int op,unsigned char a,unsigned char b,unsigned char * c)2170 static int array_binary_op_result (int op, unsigned char a, unsigned char b,
2171 unsigned char *c)
2172 {
2173 (void) op;
2174 (void) a;
2175 (void) b;
2176 *c = SLANG_ARRAY_TYPE;
2177 return 1;
2178 }
2179
array_binary_op(int op,unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp,unsigned int nb,VOID_STAR cp)2180 static int array_binary_op (int op,
2181 unsigned char a_type, VOID_STAR ap, unsigned int na,
2182 unsigned char b_type, VOID_STAR bp, unsigned int nb,
2183 VOID_STAR cp)
2184 {
2185 SLang_Array_Type *at, *bt, *ct;
2186 unsigned int i, num_dims;
2187 int (*binary_fun) (int,
2188 unsigned char, VOID_STAR, unsigned int,
2189 unsigned char, VOID_STAR, unsigned int,
2190 VOID_STAR);
2191 SLang_Class_Type *a_cl, *b_cl, *c_cl;
2192 int no_init;
2193
2194 if (a_type == SLANG_ARRAY_TYPE)
2195 {
2196 if (na != 1)
2197 {
2198 SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented");
2199 return -1;
2200 }
2201
2202 at = *(SLang_Array_Type **) ap;
2203 if (-1 == coerse_array_to_linear (at))
2204 return -1;
2205 ap = at->data;
2206 a_type = at->data_type;
2207 na = at->num_elements;
2208 }
2209 else
2210 {
2211 at = NULL;
2212 }
2213
2214 if (b_type == SLANG_ARRAY_TYPE)
2215 {
2216 if (nb != 1)
2217 {
2218 SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented");
2219 return -1;
2220 }
2221
2222 bt = *(SLang_Array_Type **) bp;
2223 if (-1 == coerse_array_to_linear (bt))
2224 return -1;
2225 bp = bt->data;
2226 b_type = bt->data_type;
2227 nb = bt->num_elements;
2228 }
2229 else
2230 {
2231 bt = NULL;
2232 }
2233
2234 if ((at != NULL) && (bt != NULL))
2235 {
2236 num_dims = at->num_dims;
2237
2238 if (num_dims != bt->num_dims)
2239 {
2240 SLang_verror (SL_TYPE_MISMATCH, "Arrays must have same dim for binary operation");
2241 return -1;
2242 }
2243
2244 for (i = 0; i < num_dims; i++)
2245 {
2246 if (at->dims[i] != bt->dims[i])
2247 {
2248 SLang_verror (SL_TYPE_MISMATCH, "Arrays must be the same for binary operation");
2249 return -1;
2250 }
2251 }
2252 }
2253
2254 a_cl = _SLclass_get_class (a_type);
2255 b_cl = _SLclass_get_class (b_type);
2256
2257 if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &c_cl, 1)))
2258 return -1;
2259
2260 no_init = ((c_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
2261 || (c_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
2262
2263 ct = NULL;
2264 #if _SLANG_USE_TMP_OPTIMIZATION
2265 /* If we are dealing with scalar (or vector) objects, and if the object
2266 * appears to be owned by the stack, then use it instead of creating a
2267 * new version. This can happen with code such as:
2268 * @ x = [1,2,3,4];
2269 * @ x = __tmp(x) + 1;
2270 */
2271 if (no_init)
2272 {
2273 if ((at != NULL)
2274 && (at->num_refs == 1)
2275 && (at->data_type == c_cl->cl_data_type))
2276 {
2277 ct = at;
2278 ct->num_refs = 2;
2279 }
2280 else if ((bt != NULL)
2281 && (bt->num_refs == 1)
2282 && (bt->data_type == c_cl->cl_data_type))
2283 {
2284 ct = bt;
2285 ct->num_refs = 2;
2286 }
2287 }
2288 #endif /* _SLANG_USE_TMP_OPTIMIZATION */
2289
2290 if (ct == NULL)
2291 {
2292 if (at != NULL) ct = at; else ct = bt;
2293 ct = SLang_create_array1 (c_cl->cl_data_type, 0, NULL, ct->dims, ct->num_dims, no_init);
2294 if (ct == NULL)
2295 return -1;
2296 }
2297
2298
2299 if ((na == 0) || (nb == 0) /* allow empty arrays */
2300 || (1 == (*binary_fun) (op, a_type, ap, na, b_type, bp, nb, ct->data)))
2301 {
2302 *(SLang_Array_Type **) cp = ct;
2303 return 1;
2304 }
2305
2306 SLang_free_array (ct);
2307 return -1;
2308 }
2309
array_where(void)2310 static void array_where (void)
2311 {
2312 SLang_Array_Type *at, *bt;
2313 char *a_data;
2314 int *b_data;
2315 unsigned int i, num_elements;
2316 int b_num;
2317
2318 if (-1 == SLang_pop_array (&at, 1))
2319 return;
2320
2321 bt = NULL;
2322
2323 if (at->data_type != SLANG_CHAR_TYPE)
2324 {
2325 int zero;
2326 SLang_Array_Type *tmp_at;
2327
2328 tmp_at = at;
2329 zero = 0;
2330 if (1 != array_binary_op (SLANG_NE,
2331 SLANG_ARRAY_TYPE, (VOID_STAR) &at, 1,
2332 SLANG_CHAR_TYPE, (VOID_STAR) &zero, 1,
2333 (VOID_STAR) &tmp_at))
2334 goto return_error;
2335
2336 SLang_free_array (at);
2337 at = tmp_at;
2338 if (at->data_type != SLANG_CHAR_TYPE)
2339 {
2340 SLang_Error = SL_TYPE_MISMATCH;
2341 goto return_error;
2342 }
2343 }
2344
2345 a_data = (char *) at->data;
2346 num_elements = at->num_elements;
2347
2348 b_num = 0;
2349 for (i = 0; i < num_elements; i++)
2350 if (a_data[i] != 0) b_num++;
2351
2352 if (NULL == (bt = SLang_create_array1 (SLANG_INT_TYPE, 0, NULL, &b_num, 1, 1)))
2353 goto return_error;
2354
2355 b_data = (int *) bt->data;
2356
2357 i = 0;
2358 while (b_num)
2359 {
2360 if (a_data[i] != 0)
2361 {
2362 *b_data++ = i;
2363 b_num--;
2364 }
2365
2366 i++;
2367 }
2368
2369 (void) SLang_push_array (bt, 0);
2370 /* drop */
2371
2372 return_error:
2373 SLang_free_array (at);
2374 SLang_free_array (bt);
2375 }
2376
do_array_reshape(SLang_Array_Type * at,SLang_Array_Type * ind_at)2377 static int do_array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
2378 {
2379 int *dims;
2380 unsigned int i, num_dims;
2381 unsigned int num_elements;
2382
2383 if ((ind_at->data_type != SLANG_INT_TYPE)
2384 || (ind_at->num_dims != 1))
2385 {
2386 SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
2387 return -1;
2388 }
2389
2390 num_dims = ind_at->num_elements;
2391 dims = (int *) ind_at->data;
2392
2393 num_elements = 1;
2394 for (i = 0; i < num_dims; i++)
2395 {
2396 int d = dims[i];
2397 if (d < 0)
2398 {
2399 SLang_verror (SL_INVALID_PARM, "reshape: dimension is less then 0");
2400 return -1;
2401 }
2402
2403 num_elements = (unsigned int) d * num_elements;
2404 }
2405
2406 if ((num_elements != at->num_elements)
2407 || (num_dims > SLARRAY_MAX_DIMS))
2408 {
2409 SLang_verror (SL_INVALID_PARM, "Unable to reshape array to specified size");
2410 return -1;
2411 }
2412
2413 for (i = 0; i < num_dims; i++)
2414 at->dims [i] = dims[i];
2415
2416 while (i < SLARRAY_MAX_DIMS)
2417 {
2418 at->dims [i] = 1;
2419 i++;
2420 }
2421
2422 at->num_dims = num_dims;
2423 return 0;
2424 }
2425
array_reshape(SLang_Array_Type * at,SLang_Array_Type * ind_at)2426 static void array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at)
2427 {
2428 (void) do_array_reshape (at, ind_at);
2429 }
2430
_array_reshape(SLang_Array_Type * ind_at)2431 static void _array_reshape (SLang_Array_Type *ind_at)
2432 {
2433 SLang_Array_Type *at;
2434 SLang_Array_Type *new_at;
2435
2436 if (-1 == SLang_pop_array (&at, 1))
2437 return;
2438
2439 /* FIXME: Priority=low: duplicate_array could me modified to look at num_refs */
2440
2441 /* Now try to avoid the overhead of creating a new array if possible */
2442 if (at->num_refs == 1)
2443 {
2444 /* Great, we are the sole owner of this array. */
2445 if ((-1 == do_array_reshape (at, ind_at))
2446 || (-1 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR)at)))
2447 SLang_free_array (at);
2448 return;
2449 }
2450
2451 new_at = SLang_duplicate_array (at);
2452 if (new_at != NULL)
2453 {
2454 if (0 == do_array_reshape (new_at, ind_at))
2455 (void) SLang_push_array (new_at, 0);
2456
2457 SLang_free_array (new_at);
2458 }
2459 SLang_free_array (at);
2460 }
2461
2462 typedef struct
2463 {
2464 SLang_Array_Type *at;
2465 unsigned int increment;
2466 char *addr;
2467 }
2468 Map_Arg_Type;
2469 /* Usage: array_map (Return-Type, func, args,....); */
array_map(void)2470 static void array_map (void)
2471 {
2472 Map_Arg_Type *args;
2473 unsigned int num_args;
2474 unsigned int i, i_control;
2475 SLang_Name_Type *nt;
2476 unsigned int num_elements;
2477 SLang_Array_Type *at;
2478 char *addr;
2479 unsigned char type;
2480
2481 at = NULL;
2482 args = NULL;
2483 nt = NULL;
2484
2485 if (SLang_Num_Function_Args < 3)
2486 {
2487 SLang_verror (SL_INVALID_PARM,
2488 "Usage: array_map (Return-Type, &func, args...)");
2489 SLdo_pop_n (SLang_Num_Function_Args);
2490 return;
2491 }
2492
2493 num_args = (unsigned int)SLang_Num_Function_Args - 2;
2494 args = (Map_Arg_Type *) SLmalloc (num_args * sizeof (Map_Arg_Type));
2495 if (args == NULL)
2496 {
2497 SLdo_pop_n (SLang_Num_Function_Args);
2498 return;
2499 }
2500 memset ((char *) args, 0, num_args * sizeof (Map_Arg_Type));
2501 i = num_args;
2502 i_control = 0;
2503 while (i > 0)
2504 {
2505 i--;
2506 if (-1 == SLang_pop_array (&args[i].at, 1))
2507 {
2508 SLdo_pop_n (i + 2);
2509 goto return_error;
2510 }
2511 if (args[i].at->num_elements > 1)
2512 i_control = i;
2513 }
2514
2515 if (NULL == (nt = SLang_pop_function ()))
2516 {
2517 SLdo_pop_n (1);
2518 goto return_error;
2519 }
2520
2521 num_elements = args[i_control].at->num_elements;
2522
2523 if (-1 == SLang_pop_datatype (&type))
2524 goto return_error;
2525
2526 if (type == SLANG_UNDEFINED_TYPE) /* Void_Type */
2527 at = NULL;
2528 else
2529 {
2530 at = args[i_control].at;
2531
2532 if (NULL == (at = SLang_create_array (type, 0, NULL, at->dims, at->num_dims)))
2533 goto return_error;
2534 }
2535
2536
2537 for (i = 0; i < num_args; i++)
2538 {
2539 SLang_Array_Type *ati = args[i].at;
2540 /* FIXME: Priority = low: The actual dimensions should be compared. */
2541 if (ati->num_elements == num_elements)
2542 args[i].increment = ati->sizeof_type;
2543 /* memset already guarantees increment to be zero */
2544
2545 /* FIXME: array_map on an empty array should return an empty array
2546 * and not generate an error.
2547 */
2548 if (ati->num_elements == 0)
2549 {
2550 SLang_verror (0, "array_map: function argument %d of %d is an empty array",
2551 i+1, num_args);
2552 goto return_error;
2553 }
2554
2555 args[i].addr = (char *) ati->data;
2556 }
2557
2558 if (at == NULL)
2559 addr = NULL;
2560 else
2561 addr = (char *)at->data;
2562
2563 for (i = 0; i < num_elements; i++)
2564 {
2565 unsigned int j;
2566
2567 if (-1 == SLang_start_arg_list ())
2568 goto return_error;
2569
2570 for (j = 0; j < num_args; j++)
2571 {
2572 if (-1 == push_element_at_addr (args[j].at,
2573 (VOID_STAR) args[j].addr,
2574 1))
2575 {
2576 SLdo_pop_n (j);
2577 goto return_error;
2578 }
2579
2580 args[j].addr += args[j].increment;
2581 }
2582
2583 if (-1 == SLang_end_arg_list ())
2584 {
2585 SLdo_pop_n (num_args);
2586 goto return_error;
2587 }
2588
2589 if (-1 == SLexecute_function (nt))
2590 goto return_error;
2591
2592 if (at == NULL)
2593 continue;
2594
2595 if (-1 == at->cl->cl_apop (type, (VOID_STAR) addr))
2596 goto return_error;
2597
2598 addr += at->sizeof_type;
2599 }
2600
2601 if (at != NULL)
2602 (void) SLang_push_array (at, 0);
2603
2604 /* drop */
2605
2606 return_error:
2607 SLang_free_array (at);
2608 SLang_free_function (nt);
2609 if (args != NULL)
2610 {
2611 for (i = 0; i < num_args; i++)
2612 SLang_free_array (args[i].at);
2613
2614 SLfree ((char *) args);
2615 }
2616 }
2617
2618 static SLang_Intrin_Fun_Type Array_Table [] =
2619 {
2620 MAKE_INTRINSIC_0("array_map", array_map, SLANG_VOID_TYPE),
2621 MAKE_INTRINSIC_0("array_sort", sort_array, SLANG_VOID_TYPE),
2622 MAKE_INTRINSIC_1("array_to_bstring", array_to_bstring, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
2623 MAKE_INTRINSIC_1("bstring_to_array", bstring_to_array, SLANG_VOID_TYPE, SLANG_BSTRING_TYPE),
2624 MAKE_INTRINSIC("init_char_array", init_char_array, SLANG_VOID_TYPE, 0),
2625 MAKE_INTRINSIC("array_info", array_info, SLANG_VOID_TYPE, 0),
2626 MAKE_INTRINSIC("where", array_where, SLANG_VOID_TYPE, 0),
2627 MAKE_INTRINSIC_2("reshape", array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE),
2628 MAKE_INTRINSIC_1("_reshape", _array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE),
2629 SLANG_END_INTRIN_FUN_TABLE
2630 };
2631
array_string(unsigned char type,VOID_STAR v)2632 static char *array_string (unsigned char type, VOID_STAR v)
2633 {
2634 SLang_Array_Type *at;
2635 char buf[512];
2636 unsigned int i, num_dims;
2637 int *dims;
2638
2639 at = *(SLang_Array_Type **) v;
2640 type = at->data_type;
2641 num_dims = at->num_dims;
2642 dims = at->dims;
2643
2644 sprintf (buf, "%s[%d", SLclass_get_datatype_name (type), at->dims[0]);
2645
2646 for (i = 1; i < num_dims; i++)
2647 sprintf (buf + strlen(buf), ",%d", dims[i]);
2648 strcat (buf, "]");
2649
2650 return SLmake_string (buf);
2651 }
2652
array_destroy(unsigned char type,VOID_STAR v)2653 static void array_destroy (unsigned char type, VOID_STAR v)
2654 {
2655 (void) type;
2656 SLang_free_array (*(SLang_Array_Type **) v);
2657 }
2658
array_push(unsigned char type,VOID_STAR v)2659 static int array_push (unsigned char type, VOID_STAR v)
2660 {
2661 SLang_Array_Type *at;
2662
2663 (void) type;
2664 at = *(SLang_Array_Type **) v;
2665 return SLang_push_array (at, 0);
2666 }
2667
2668 /* Intrinsic arrays are not stored in a variable. So, the address that
2669 * would contain the variable holds the array address.
2670 */
array_push_intrinsic(unsigned char type,VOID_STAR v)2671 static int array_push_intrinsic (unsigned char type, VOID_STAR v)
2672 {
2673 (void) type;
2674 return SLang_push_array ((SLang_Array_Type *) v, 0);
2675 }
2676
_SLarray_add_bin_op(unsigned char type)2677 int _SLarray_add_bin_op (unsigned char type)
2678 {
2679 SL_OOBinary_Type *ab;
2680 SLang_Class_Type *cl;
2681
2682 cl = _SLclass_get_class (type);
2683 ab = cl->cl_binary_ops;
2684
2685 while (ab != NULL)
2686 {
2687 if (ab->data_type == SLANG_ARRAY_TYPE)
2688 return 0;
2689 ab = ab->next;
2690 }
2691
2692 if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, type, array_binary_op, array_binary_op_result))
2693 || (-1 == SLclass_add_binary_op (type, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result)))
2694 return -1;
2695
2696 return 0;
2697 }
2698
2699 static SLang_Array_Type *
do_array_math_op(int op,int unary_type,SLang_Array_Type * at,unsigned int na)2700 do_array_math_op (int op, int unary_type,
2701 SLang_Array_Type *at, unsigned int na)
2702 {
2703 unsigned char a_type, b_type;
2704 int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR);
2705 SLang_Array_Type *bt;
2706 SLang_Class_Type *b_cl;
2707 int no_init;
2708
2709 if (na != 1)
2710 {
2711 SLang_verror (SL_NOT_IMPLEMENTED, "Operation restricted to 1 array");
2712 return NULL;
2713 }
2714
2715 a_type = at->data_type;
2716 if (NULL == (f = _SLclass_get_unary_fun (op, at->cl, &b_cl, unary_type)))
2717 return NULL;
2718 b_type = b_cl->cl_data_type;
2719
2720 if (-1 == coerse_array_to_linear (at))
2721 return NULL;
2722
2723 no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
2724 || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
2725
2726 #if _SLANG_USE_TMP_OPTIMIZATION
2727 /* If we are dealing with scalar (or vector) objects, and if the object
2728 * appears to be owned by the stack, then use it instead of creating a
2729 * new version. This can happen with code such as:
2730 * @ x = [1,2,3,4];
2731 * @ x = UNARY_OP(__tmp(x));
2732 */
2733 if (no_init
2734 && (at->num_refs == 1)
2735 && (at->data_type == b_cl->cl_data_type))
2736 {
2737 bt = at;
2738 bt->num_refs = 2;
2739 }
2740 else
2741 #endif /* _SLANG_USE_TMP_OPTIMIZATION */
2742 if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
2743 return NULL;
2744
2745 if (1 != (*f)(op, a_type, at->data, at->num_elements, bt->data))
2746 {
2747 SLang_free_array (bt);
2748 return NULL;
2749 }
2750 return bt;
2751 }
2752
2753 static int
array_unary_op_result(int op,unsigned char a,unsigned char * b)2754 array_unary_op_result (int op, unsigned char a, unsigned char *b)
2755 {
2756 (void) op;
2757 (void) a;
2758 *b = SLANG_ARRAY_TYPE;
2759 return 1;
2760 }
2761
2762 static int
array_unary_op(int op,unsigned char a,VOID_STAR ap,unsigned int na,VOID_STAR bp)2763 array_unary_op (int op,
2764 unsigned char a, VOID_STAR ap, unsigned int na,
2765 VOID_STAR bp)
2766 {
2767 SLang_Array_Type *at;
2768
2769 (void) a;
2770 at = *(SLang_Array_Type **) ap;
2771 if (NULL == (at = do_array_math_op (op, _SLANG_BC_UNARY, at, na)))
2772 {
2773 if (SLang_Error) return -1;
2774 return 0;
2775 }
2776 *(SLang_Array_Type **) bp = at;
2777 return 1;
2778 }
2779
2780 static int
array_math_op(int op,unsigned char a,VOID_STAR ap,unsigned int na,VOID_STAR bp)2781 array_math_op (int op,
2782 unsigned char a, VOID_STAR ap, unsigned int na,
2783 VOID_STAR bp)
2784 {
2785 SLang_Array_Type *at;
2786
2787 (void) a;
2788 at = *(SLang_Array_Type **) ap;
2789 if (NULL == (at = do_array_math_op (op, _SLANG_BC_MATH_UNARY, at, na)))
2790 {
2791 if (SLang_Error) return -1;
2792 return 0;
2793 }
2794 *(SLang_Array_Type **) bp = at;
2795 return 1;
2796 }
2797
2798 static int
array_app_op(int op,unsigned char a,VOID_STAR ap,unsigned int na,VOID_STAR bp)2799 array_app_op (int op,
2800 unsigned char a, VOID_STAR ap, unsigned int na,
2801 VOID_STAR bp)
2802 {
2803 SLang_Array_Type *at;
2804
2805 (void) a;
2806 at = *(SLang_Array_Type **) ap;
2807 if (NULL == (at = do_array_math_op (op, _SLANG_BC_APP_UNARY, at, na)))
2808 {
2809 if (SLang_Error) return -1;
2810 return 0;
2811 }
2812 *(SLang_Array_Type **) bp = at;
2813 return 1;
2814 }
2815
2816 int
_SLarray_typecast(unsigned char a_type,VOID_STAR ap,unsigned int na,unsigned char b_type,VOID_STAR bp,int is_implicit)2817 _SLarray_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na,
2818 unsigned char b_type, VOID_STAR bp,
2819 int is_implicit)
2820 {
2821 SLang_Array_Type *at, *bt;
2822 SLang_Class_Type *b_cl;
2823 int no_init;
2824 int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR);
2825
2826 if (na != 1)
2827 {
2828 SLang_verror (SL_NOT_IMPLEMENTED, "typecast of multiple arrays not implemented");
2829 return -1;
2830 }
2831
2832 at = *(SLang_Array_Type **) ap;
2833 a_type = at->data_type;
2834
2835 if (a_type == b_type)
2836 {
2837 at->num_refs += 1;
2838 *(SLang_Array_Type **) bp = at;
2839 return 1;
2840 }
2841
2842 if (NULL == (t = _SLclass_get_typecast (a_type, b_type, is_implicit)))
2843 return -1;
2844
2845 if (-1 == coerse_array_to_linear (at))
2846 return -1;
2847
2848 b_cl = _SLclass_get_class (b_type);
2849
2850 no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
2851 || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR));
2852
2853 if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init)))
2854 return -1;
2855
2856 if (1 == (*t) (a_type, at->data, at->num_elements, b_type, bt->data))
2857 {
2858 *(SLang_Array_Type **) bp = bt;
2859 return 1;
2860 }
2861
2862 SLang_free_array (bt);
2863 return 0;
2864 }
2865
SLang_duplicate_array(SLang_Array_Type * at)2866 SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *at)
2867 {
2868 SLang_Array_Type *bt;
2869 char *data, *a_data;
2870 unsigned int i, num_elements, sizeof_type;
2871 unsigned int size;
2872 int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR);
2873 unsigned char type;
2874
2875 if (-1 == coerse_array_to_linear (at))
2876 return NULL;
2877
2878 type = at->data_type;
2879 num_elements = at->num_elements;
2880 sizeof_type = at->sizeof_type;
2881 size = num_elements * sizeof_type;
2882
2883 if (NULL == (data = SLmalloc (size)))
2884 return NULL;
2885
2886 if (NULL == (bt = SLang_create_array (type, 0, (VOID_STAR)data, at->dims, at->num_dims)))
2887 {
2888 SLfree (data);
2889 return NULL;
2890 }
2891
2892 a_data = (char *) at->data;
2893 if (0 == (at->flags & SLARR_DATA_VALUE_IS_POINTER))
2894 {
2895 SLMEMCPY (data, a_data, size);
2896 return bt;
2897 }
2898
2899 SLMEMSET (data, 0, size);
2900
2901 cl_acopy = at->cl->cl_acopy;
2902 for (i = 0; i < num_elements; i++)
2903 {
2904 if (NULL != *(VOID_STAR *) a_data)
2905 {
2906 if (-1 == (*cl_acopy) (type, (VOID_STAR) a_data, (VOID_STAR) data))
2907 {
2908 SLang_free_array (bt);
2909 return NULL;
2910 }
2911 }
2912
2913 data += sizeof_type;
2914 a_data += sizeof_type;
2915 }
2916
2917 return bt;
2918 }
2919
array_dereference(unsigned char type,VOID_STAR addr)2920 static int array_dereference (unsigned char type, VOID_STAR addr)
2921 {
2922 SLang_Array_Type *at;
2923
2924 (void) type;
2925 at = SLang_duplicate_array (*(SLang_Array_Type **) addr);
2926 if (at == NULL) return -1;
2927 return SLang_push_array (at, 1);
2928 }
2929
2930 /* This function gets called via, e.g., @Array_Type (Double_Type, [10,20]);
2931 */
2932 static int
array_datatype_deref(unsigned char type)2933 array_datatype_deref (unsigned char type)
2934 {
2935 SLang_Array_Type *ind_at;
2936 SLang_Array_Type *at;
2937
2938 #if 0
2939 /* The parser generated code for this as if a function call were to be
2940 * made. However, the interpreter simply called the deref object routine
2941 * instead of the function call. So, I must simulate the function call.
2942 * This needs to be formalized to hide this detail from applications
2943 * who wish to do the same. So...
2944 * FIXME: Priority=medium
2945 */
2946 if (0 == _SL_increment_frame_pointer ())
2947 (void) _SL_decrement_frame_pointer ();
2948 #endif
2949
2950 if (-1 == SLang_pop_array (&ind_at, 1))
2951 return -1;
2952
2953 if ((ind_at->data_type != SLANG_INT_TYPE)
2954 || (ind_at->num_dims != 1))
2955 {
2956 SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array");
2957 goto return_error;
2958 }
2959
2960 if (-1 == SLang_pop_datatype (&type))
2961 goto return_error;
2962
2963 if (NULL == (at = SLang_create_array (type, 0, NULL,
2964 (int *) ind_at->data,
2965 ind_at->num_elements)))
2966 goto return_error;
2967
2968 SLang_free_array (ind_at);
2969 return SLang_push_array (at, 1);
2970
2971 return_error:
2972 SLang_free_array (ind_at);
2973 return -1;
2974 }
2975
array_length(unsigned char type,VOID_STAR v,unsigned int * len)2976 static int array_length (unsigned char type, VOID_STAR v, unsigned int *len)
2977 {
2978 SLang_Array_Type *at;
2979
2980 (void) type;
2981 at = *(SLang_Array_Type **) v;
2982 *len = at->num_elements;
2983 return 0;
2984 }
2985
2986 int
_SLarray_init_slarray(void)2987 _SLarray_init_slarray (void)
2988 {
2989 SLang_Class_Type *cl;
2990
2991 if (-1 == SLadd_intrin_fun_table (Array_Table, NULL))
2992 return -1;
2993
2994 if (NULL == (cl = SLclass_allocate_class ("Array_Type")))
2995 return -1;
2996
2997 (void) SLclass_set_string_function (cl, array_string);
2998 (void) SLclass_set_destroy_function (cl, array_destroy);
2999 (void) SLclass_set_push_function (cl, array_push);
3000 cl->cl_push_intrinsic = array_push_intrinsic;
3001 cl->cl_dereference = array_dereference;
3002 cl->cl_datatype_deref = array_datatype_deref;
3003 cl->cl_length = array_length;
3004
3005 if (-1 == SLclass_register_class (cl, SLANG_ARRAY_TYPE, sizeof (VOID_STAR),
3006 SLANG_CLASS_TYPE_PTR))
3007 return -1;
3008
3009 if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result))
3010 || (-1 == SLclass_add_unary_op (SLANG_ARRAY_TYPE, array_unary_op, array_unary_op_result))
3011 || (-1 == SLclass_add_app_unary_op (SLANG_ARRAY_TYPE, array_app_op, array_unary_op_result))
3012 || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result))
3013 || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result)))
3014 return -1;
3015
3016 return 0;
3017 }
3018
SLang_pop_array(SLang_Array_Type ** at_ptr,int convert_scalar)3019 int SLang_pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
3020 {
3021 if (-1 == pop_array (at_ptr, convert_scalar))
3022 return -1;
3023
3024 if (-1 == coerse_array_to_linear (*at_ptr))
3025 {
3026 SLang_free_array (*at_ptr);
3027 return -1;
3028 }
3029 return 0;
3030 }
3031
SLang_pop_array_of_type(SLang_Array_Type ** at,unsigned char type)3032 int SLang_pop_array_of_type (SLang_Array_Type **at, unsigned char type)
3033 {
3034 if (-1 == SLclass_typecast (type, 1, 1))
3035 return -1;
3036
3037 return SLang_pop_array (at, 1);
3038 }
3039
3040 void (*_SLang_Matrix_Multiply)(void);
3041
_SLarray_matrix_multiply(void)3042 int _SLarray_matrix_multiply (void)
3043 {
3044 if (_SLang_Matrix_Multiply != NULL)
3045 {
3046 (*_SLang_Matrix_Multiply)();
3047 return 0;
3048 }
3049 SLang_verror (SL_NOT_IMPLEMENTED, "Matrix multiplication not available");
3050 return -1;
3051 }
3052
3053 struct _SLang_Foreach_Context_Type
3054 {
3055 SLang_Array_Type *at;
3056 unsigned int next_element_index;
3057 };
3058
3059 SLang_Foreach_Context_Type *
_SLarray_cl_foreach_open(SLtype type,unsigned int num)3060 _SLarray_cl_foreach_open (SLtype type, unsigned int num)
3061 {
3062 SLang_Foreach_Context_Type *c;
3063
3064 if (num != 0)
3065 {
3066 SLdo_pop_n (num + 1);
3067 SLang_verror (SL_NOT_IMPLEMENTED,
3068 "%s does not support 'foreach using' form",
3069 SLclass_get_datatype_name (type));
3070 return NULL;
3071 }
3072
3073 if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type))))
3074 return NULL;
3075
3076 memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type));
3077
3078 if (-1 == pop_array (&c->at, 1))
3079 {
3080 SLfree ((char *) c);
3081 return NULL;
3082 }
3083
3084 return c;
3085 }
3086
_SLarray_cl_foreach_close(SLtype type,SLang_Foreach_Context_Type * c)3087 void _SLarray_cl_foreach_close (SLtype type, SLang_Foreach_Context_Type *c)
3088 {
3089 (void) type;
3090 if (c == NULL) return;
3091 SLang_free_array (c->at);
3092 SLfree ((char *) c);
3093 }
3094
_SLarray_cl_foreach(SLtype type,SLang_Foreach_Context_Type * c)3095 int _SLarray_cl_foreach (SLtype type, SLang_Foreach_Context_Type *c)
3096 {
3097 SLang_Array_Type *at;
3098 VOID_STAR data;
3099
3100 (void) type;
3101
3102 if (c == NULL)
3103 return -1;
3104
3105 at = c->at;
3106 if (at->num_elements == c->next_element_index)
3107 return 0;
3108
3109 /* FIXME: Priority = low. The following assumes linear arrays
3110 * or Integer range arrays. Fixing it right requires a method to get the
3111 * nth element of a multidimensional array.
3112 */
3113
3114 if (at->flags & SLARR_DATA_VALUE_IS_RANGE)
3115 {
3116 int d = (int) c->next_element_index;
3117 data = range_get_data_addr (at, &d);
3118 }
3119 else
3120 data = (VOID_STAR) ((char *)at->data + (c->next_element_index * at->sizeof_type));
3121
3122 c->next_element_index += 1;
3123
3124 if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
3125 && (*(VOID_STAR *) data == NULL))
3126 {
3127 if (-1 == SLang_push_null ())
3128 return -1;
3129 }
3130 else if (-1 == (*at->cl->cl_apush)(at->data_type, data))
3131 return -1;
3132
3133 /* keep going */
3134 return 1;
3135 }
3136
3137