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