Main Page | Class List | Directories | File List | Class Members | File Members

slarray.c

Go to the documentation of this file.
00001 /* Array manipulation routines for S-Lang */
00002 /*
00003 Copyright (C) 2004, 2005, 2006 John E. Davis
00004 
00005 This file is part of the S-Lang Library.
00006 
00007 The S-Lang Library is free software; you can redistribute it and/or
00008 modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the
00010 License, or (at your option) any later version.
00011 
00012 The S-Lang Library is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this library; if not, write to the Free Software
00019 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00020 USA.  
00021 */
00022 
00023 
00024 #include "slinclud.h"
00025 
00026 /* #define SL_APP_WANTS_FOREACH */
00027 #include "slang.h"
00028 #include "_slang.h"
00029 
00030 typedef struct Range_Array_Type SLarray_Range_Array_Type;
00031 
00032 struct Range_Array_Type
00033 {
00034    SLindex_Type first_index;
00035    SLindex_Type last_index;
00036    SLindex_Type delta;
00037    int has_first_index;
00038    int has_last_index;
00039    int (*to_linear_fun) (SLang_Array_Type *, SLarray_Range_Array_Type *, VOID_STAR);
00040 };
00041 
00042 static SLang_Array_Type *inline_implicit_int_array (SLindex_Type *, SLindex_Type *, SLindex_Type *);
00043 
00044 /* Use SLang_pop_array when a linear array is required. */
00045 static int pop_array (SLang_Array_Type **at_ptr, int convert_scalar)
00046 {
00047    SLang_Array_Type *at;
00048    SLindex_Type one = 1;
00049    int type;
00050 
00051    *at_ptr = NULL;
00052    type = SLang_peek_at_stack ();
00053 
00054    switch (type)
00055      {
00056       case -1:
00057         return -1;
00058 
00059       case SLANG_ARRAY_TYPE:
00060         return SLclass_pop_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR *) at_ptr);
00061 
00062       case SLANG_NULL_TYPE:
00063         /* convert_scalar = 0; */  /* commented out for 2.0.5 to fix array_map NULL bug */
00064         /* drop */
00065       default:
00066         if (convert_scalar == 0)
00067           {
00068              SLdo_pop ();
00069              SLang_verror (SL_TYPE_MISMATCH, "Context requires an array.  Scalar not converted");
00070              return -1;
00071           }
00072         break;
00073      }
00074 
00075    if (NULL == (at = SLang_create_array ((SLtype) type, 0, NULL, &one, 1)))
00076      return -1;
00077 
00078    if (at->flags & SLARR_DATA_VALUE_IS_POINTER)
00079      {
00080         /* The act of creating the array could have initialized the array
00081          * with pointers to an object of the type.  For example, this could
00082          * happen with user-defined structs.
00083          */
00084         if (*(VOID_STAR *)at->data != NULL)
00085           {
00086              at->cl->cl_destroy ((SLtype) type, at->data);
00087              *(VOID_STAR *) at->data = NULL;
00088           }
00089      }
00090 
00091    if (-1 == at->cl->cl_apop ((SLtype) type, at->data))
00092      {
00093         SLang_free_array (at);
00094         return -1;
00095      }
00096 
00097    *at_ptr = at;
00098 
00099    return 0;
00100 }
00101 
00102 static VOID_STAR linear_get_data_addr (SLang_Array_Type *at, SLindex_Type *dims)
00103 {
00104    size_t ofs;
00105 
00106    if (at->num_dims == 1)
00107      {
00108         if (*dims < 0)
00109           ofs = (size_t) (*dims + at->dims[0]);
00110         else
00111           ofs = (size_t)*dims;
00112      }
00113    else 
00114      {
00115         unsigned int i;
00116         SLindex_Type *max_dims = at->dims;
00117         unsigned int num_dims = at->num_dims;
00118         ofs = 0;
00119         for (i = 0; i < num_dims; i++)
00120           {
00121              SLindex_Type d = dims[i];
00122              
00123              if (d < 0)
00124                d = d + max_dims[i];
00125              
00126              ofs = ofs * (size_t)max_dims [i] + (size_t) d;
00127           }
00128      }
00129    if (ofs >= at->num_elements)
00130      {
00131         SLang_set_error (SL_Index_Error);
00132         return NULL;
00133      }
00134    return (VOID_STAR) ((char *)at->data + (ofs * at->sizeof_type));
00135 }
00136 
00137 _INLINE_
00138 static VOID_STAR get_data_addr (SLang_Array_Type *at, SLindex_Type *dims)
00139 {
00140    VOID_STAR data;
00141 
00142    data = at->data;
00143    if (data == NULL)
00144      {
00145         SLang_verror (SL_UNKNOWN_ERROR, "Array has no data");
00146         return NULL;
00147      }
00148 
00149    data = (*at->index_fun) (at, dims);
00150 
00151    if (data == NULL)
00152      {
00153         SLang_verror (SL_UNKNOWN_ERROR, "Unable to access array element");
00154         return NULL;
00155      }
00156 
00157    return data;
00158 }
00159 
00160 void _pSLarray_free_array_elements (SLang_Class_Type *cl, VOID_STAR s, SLuindex_Type num)
00161 {
00162    size_t sizeof_type;
00163    void (*f) (SLtype, VOID_STAR);
00164    char *p;
00165    SLtype type;
00166 
00167    if ((cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR)
00168        || (cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR))
00169      return;
00170 
00171    f = cl->cl_destroy;
00172    sizeof_type = cl->cl_sizeof_type;
00173    type = cl->cl_data_type;
00174 
00175    p = (char *) s;
00176    while (num != 0)
00177      {
00178         if (NULL != *(VOID_STAR *)p)
00179           {
00180              (*f) (type, (VOID_STAR)p);
00181              *(VOID_STAR *) p = NULL;
00182           }
00183         p += sizeof_type;
00184         num--;
00185      }
00186 }
00187 
00188 static int destroy_element (SLang_Array_Type *at,
00189                             SLindex_Type *dims,
00190                             VOID_STAR data)
00191 {
00192    data = get_data_addr (at, dims);
00193    if (data == NULL)
00194      return -1;
00195 
00196    /* This function should only get called for arrays that have
00197     * pointer elements.  Do not call the destroy method if the element
00198     * is NULL.
00199     */
00200    if (NULL != *(VOID_STAR *)data)
00201      {
00202         (*at->cl->cl_destroy) (at->data_type, data);
00203         *(VOID_STAR *) data = NULL;
00204      }
00205    return 0;
00206 }
00207 
00208 /* This function only gets called when a new array is created.  Thus there
00209  * is no need to destroy the object first.
00210  */
00211 static int new_object_element (SLang_Array_Type *at,
00212                                SLindex_Type *dims,
00213                                VOID_STAR data)
00214 {
00215    data = get_data_addr (at, dims);
00216    if (data == NULL)
00217      return -1;
00218 
00219    return (*at->cl->cl_init_array_object) (at->data_type, data);
00220 }
00221 
00222 int _pSLarray_next_index (SLindex_Type *dims, SLindex_Type *max_dims, unsigned int num_dims)
00223 {
00224    while (num_dims)
00225      {
00226         SLindex_Type dims_i;
00227 
00228         num_dims--;
00229 
00230         dims_i = dims [num_dims] + 1;
00231         if (dims_i < (int) max_dims [num_dims])
00232           {
00233              dims [num_dims] = dims_i;
00234              return 0;
00235           }
00236         dims [num_dims] = 0;
00237      }
00238 
00239    return -1;
00240 }
00241 
00242 static int do_method_for_all_elements (SLang_Array_Type *at,
00243                                        int (*method)(SLang_Array_Type *,
00244                                                      SLindex_Type *,
00245                                                      VOID_STAR),
00246                                        VOID_STAR client_data)
00247 {
00248    SLindex_Type dims [SLARRAY_MAX_DIMS];
00249    SLindex_Type *max_dims;
00250    unsigned int num_dims;
00251 
00252    if (at->num_elements == 0)
00253      return 0;
00254 
00255    max_dims = at->dims;
00256    num_dims = at->num_dims;
00257 
00258    SLMEMSET((char *)dims, 0, sizeof(dims));
00259 
00260    do
00261      {
00262         if (-1 == (*method) (at, dims, client_data))
00263           return -1;
00264      }
00265    while (0 == _pSLarray_next_index (dims, max_dims, num_dims));
00266 
00267    return 0;
00268 }
00269 
00270 void SLang_free_array (SLang_Array_Type *at)
00271 {
00272    unsigned int flags;
00273 
00274    if (at == NULL) return;
00275 
00276    if (at->num_refs > 1)
00277      {
00278         at->num_refs -= 1;
00279         return;
00280      }
00281 
00282    flags = at->flags;
00283 
00284    if (flags & SLARR_DATA_VALUE_IS_INTRINSIC)
00285      return;                           /* not to be freed */
00286 
00287    if (flags & SLARR_DATA_VALUE_IS_POINTER)
00288      (void) do_method_for_all_elements (at, destroy_element, NULL);
00289 
00290    if (at->free_fun != NULL)
00291      at->free_fun (at);
00292    else
00293      SLfree ((char *) at->data);
00294 
00295    SLfree ((char *) at);
00296 }
00297 
00298 SLang_Array_Type *
00299 SLang_create_array1 (SLtype type, int read_only, VOID_STAR data,
00300                      SLindex_Type *dims, unsigned int num_dims, int no_init)
00301 {
00302    SLang_Class_Type *cl;
00303    SLang_Array_Type *at;
00304    SLuindex_Type i, num_elements;
00305    size_t sizeof_type;
00306    size_t size;
00307 
00308    if (num_dims > SLARRAY_MAX_DIMS)
00309      {
00310         SLang_verror (SL_NOT_IMPLEMENTED, "%u dimensional arrays are not supported", num_dims);
00311         return NULL;
00312      }
00313 
00314    for (i = 0; i < num_dims; i++)
00315      {
00316         if (dims[i] < 0)
00317           {
00318              SLang_verror (SL_INVALID_PARM, "Size of array dim %u is less than 0", i);
00319              return NULL;
00320           }
00321      }
00322 
00323    cl = _pSLclass_get_class (type);
00324 
00325    at = (SLang_Array_Type *) SLmalloc (sizeof(SLang_Array_Type));
00326    if (at == NULL)
00327      return NULL;
00328 
00329    memset ((char*) at, 0, sizeof(SLang_Array_Type));
00330 
00331    at->data_type = type;
00332    at->cl = cl;
00333    at->num_dims = num_dims;
00334    at->num_refs = 1;
00335 
00336    if (read_only) at->flags = SLARR_DATA_VALUE_IS_READ_ONLY;
00337 
00338    if ((cl->cl_class_type != SLANG_CLASS_TYPE_SCALAR)
00339        && (cl->cl_class_type != SLANG_CLASS_TYPE_VECTOR))
00340      at->flags |= SLARR_DATA_VALUE_IS_POINTER;
00341 
00342    num_elements = 1;
00343    for (i = 0; i < num_dims; i++)
00344      {
00345         at->dims[i] = dims[i];
00346         num_elements = dims[i] * num_elements;
00347      }
00348 
00349    /* Now set the rest of the unused dimensions to 1.  This makes it easier
00350     * when transposing arrays.
00351     */
00352    while (i < SLARRAY_MAX_DIMS)
00353      at->dims[i++] = 1;
00354 
00355    at->num_elements = num_elements;
00356    at->index_fun = linear_get_data_addr;
00357    at->sizeof_type = sizeof_type = cl->cl_sizeof_type;
00358 
00359    if (data != NULL)
00360      {
00361         at->data = data;
00362         return at;
00363      }
00364 
00365    size = (size_t) (num_elements * sizeof_type);
00366    if (size/sizeof_type != num_elements)
00367      {
00368         SLang_verror (SL_INVALID_PARM, "Unable to create array of the desired size");
00369         SLang_free_array (at);
00370         return NULL;
00371      }
00372 
00373    if (size == 0) size = 1;
00374 
00375    if (NULL == (data = (VOID_STAR) SLmalloc (size)))
00376      {
00377         SLang_free_array (at);
00378         return NULL;
00379      }
00380 
00381    at->data = data;
00382 
00383    if ((no_init == 0) || (at->flags & SLARR_DATA_VALUE_IS_POINTER))
00384      memset ((char *) data, 0, size);
00385    
00386    if ((no_init == 0)
00387        && (cl->cl_init_array_object != NULL)
00388        && (-1 == do_method_for_all_elements (at, new_object_element, NULL)))
00389      {
00390         SLang_free_array (at);
00391         return NULL;
00392      }
00393 
00394    return at;
00395 }
00396 
00397 SLang_Array_Type *
00398 SLang_create_array (SLtype type, int read_only, VOID_STAR data,
00399                     SLindex_Type *dims, unsigned int num_dims)
00400 {
00401    return SLang_create_array1 (type, read_only, data, dims, num_dims, 0);
00402 }
00403 
00404 int SLang_add_intrinsic_array (char *name,
00405                                SLtype type,
00406                                int read_only,
00407                                VOID_STAR data,
00408                                unsigned int num_dims, ...)
00409 {
00410    va_list ap;
00411    unsigned int i;
00412    SLindex_Type dims[SLARRAY_MAX_DIMS];
00413    SLang_Array_Type *at;
00414 
00415    if ((num_dims > SLARRAY_MAX_DIMS)
00416        || (name == NULL)
00417        || (data == NULL))
00418      {
00419         SLang_verror (SL_INVALID_PARM, "Unable to create intrinsic array");
00420         return -1;
00421      }
00422 
00423    va_start (ap, num_dims);
00424    for (i = 0; i < num_dims; i++)
00425      dims [i] = va_arg (ap, int);
00426    va_end (ap);
00427 
00428    at = SLang_create_array (type, read_only, data, dims, num_dims);
00429    if (at == NULL)
00430      return -1;
00431    at->flags |= SLARR_DATA_VALUE_IS_INTRINSIC;
00432 
00433    /* Note: The variable that refers to the intrinsic array is regarded as
00434     * read-only.  That way, Array_Name = another_array; will fail.
00435     */
00436    if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) at, SLANG_ARRAY_TYPE, 1))
00437      {
00438         SLang_free_array (at);
00439         return -1;
00440      }
00441    return 0;
00442 }
00443 
00444 static int pop_array_indices (SLindex_Type *dims, unsigned int num_dims)
00445 {
00446    unsigned int n;
00447    int i;
00448 
00449    if (num_dims > SLARRAY_MAX_DIMS)
00450      {
00451         SLang_verror (SL_INVALID_PARM, "Array size not supported");
00452         return -1;
00453      }
00454 
00455    n = num_dims;
00456    while (n != 0)
00457      {
00458         n--;
00459         if (-1 == SLang_pop_integer (&i))
00460           return -1;
00461 
00462         dims[n] = i;
00463      }
00464 
00465    return 0;
00466 }
00467 
00468 int SLang_push_array (SLang_Array_Type *at, int free_flag)
00469 {
00470    if (at == NULL)
00471      return SLang_push_null ();
00472 
00473    at->num_refs += 1;
00474 
00475    if (0 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR) at))
00476      {
00477         if (free_flag)
00478           SLang_free_array (at);
00479         return 0;
00480      }
00481 
00482    at->num_refs -= 1;
00483 
00484    if (free_flag) SLang_free_array (at);
00485    return -1;
00486 }
00487 
00488 /* This function gets called via expressions such as Double_Type[10, 20];
00489  */
00490 static int push_create_new_array (unsigned int num_dims)
00491 {
00492    SLang_Array_Type *at;
00493    SLtype type;
00494    SLindex_Type dims [SLARRAY_MAX_DIMS];
00495    int (*anew) (SLtype, unsigned int);
00496 
00497    if (-1 == SLang_pop_datatype (&type))
00498      return -1;
00499 
00500    anew = (_pSLclass_get_class (type))->cl_anew;
00501    if (anew != NULL)
00502      return (*anew) (type, num_dims);
00503 
00504    if (-1 == pop_array_indices (dims, num_dims))
00505      return -1;
00506 
00507    if (NULL == (at = SLang_create_array (type, 0, NULL, dims, num_dims)))
00508      return -1;
00509 
00510    return SLang_push_array (at, 1);
00511 }
00512 
00513 static int push_element_at_addr (SLang_Array_Type *at,
00514                                  VOID_STAR data, int allow_null)
00515 {
00516    SLang_Class_Type *cl;
00517 
00518    cl = at->cl;
00519    if ((at->flags & SLARR_DATA_VALUE_IS_POINTER)
00520        && (*(VOID_STAR *) data == NULL))
00521      {
00522         if (allow_null)
00523           return SLang_push_null ();
00524 
00525         SLang_verror (SL_VARIABLE_UNINITIALIZED,
00526                       "%s array has uninitialized element", cl->cl_name);
00527         return -1;
00528      }
00529 
00530    return (*cl->cl_apush)(at->data_type, data);
00531 }
00532 
00533 static int coerse_array_to_linear (SLang_Array_Type *at)
00534 {
00535    SLarray_Range_Array_Type *range;
00536    VOID_STAR vdata;
00537    SLuindex_Type imax;
00538 
00539    /* FIXME: Priority = low.  This assumes that if an array is not linear, then
00540     * it is a range.
00541     */
00542    if (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE))
00543      return 0;
00544 
00545    range = (SLarray_Range_Array_Type *) at->data;
00546    if ((range->has_last_index == 0) || (range->has_first_index == 0))
00547      {
00548         SLang_verror (SL_INVALID_PARM, "Invalid context for a range array of indeterminate size");
00549         return -1;
00550      }
00551 
00552    imax = at->num_elements;
00553    vdata = (VOID_STAR) SLmalloc ((imax + 1) * at->sizeof_type);
00554    if (vdata == NULL)
00555      return -1;
00556    (void) (*range->to_linear_fun)(at, range, vdata);
00557    SLfree ((char *) range);
00558    at->data = (VOID_STAR) vdata;
00559    at->flags &= ~SLARR_DATA_VALUE_IS_RANGE;
00560    at->index_fun = linear_get_data_addr;
00561    return 0;
00562 }
00563 
00564 static void
00565 free_index_objects (SLang_Object_Type *index_objs, unsigned int num_indices)
00566 {
00567    unsigned int i;
00568    SLang_Object_Type *obj;
00569 
00570    for (i = 0; i < num_indices; i++)
00571      {
00572         obj = index_objs + i;
00573         if (obj->data_type != 0)
00574           SLang_free_object (obj);
00575      }
00576 }
00577 
00578 static int
00579 pop_indices (SLang_Array_Type *at_to_index,
00580              SLang_Object_Type *index_objs, unsigned int num_indices,
00581              int *is_index_array)
00582 {
00583    unsigned int i;
00584 
00585    memset((char *) index_objs, 0, num_indices * sizeof (SLang_Object_Type));
00586 
00587    *is_index_array = 0;
00588 
00589    if (num_indices != at_to_index->num_dims)
00590      {
00591         if (num_indices != 1)          /* when 1, it is an index array */
00592           {
00593              SLang_verror (SL_INVALID_PARM, "wrong number of indices for array");
00594              return -1;
00595           }
00596      }
00597 
00598    i = num_indices;
00599    while (i != 0)
00600      {
00601         SLang_Object_Type *obj;
00602         SLtype data_type;
00603         SLang_Array_Type *at;
00604 
00605         i--;
00606         obj = index_objs + i;
00607         if (SLANG_ARRAY_TYPE != _pSLang_peek_at_stack2 (&data_type))
00608           {
00609              if (-1 == _pSLang_pop_object_of_type (SLANG_ARRAY_INDEX_TYPE, obj, 0))
00610                goto return_error;
00611              
00612              continue;
00613           }
00614         if (data_type != SLANG_ARRAY_INDEX_TYPE)
00615           {
00616              if (-1 == SLclass_typecast (SLANG_ARRAY_INDEX_TYPE, 1, 1))
00617                return -1;
00618           }
00619         if (-1 == SLang_pop (obj))
00620           goto return_error;
00621 
00622         at = obj->v.array_val;
00623         if (at->flags & SLARR_DATA_VALUE_IS_RANGE)
00624           {
00625              SLarray_Range_Array_Type *r = (SLarray_Range_Array_Type *) at->data;
00626              if ((r->has_last_index == 0) || (r->has_first_index == 0))
00627                {
00628                   /* Cases to consider (positive increment)
00629                    *   [:]  ==> [0:n-1] all elements
00630                    *   [:i] ==> [0:i] for i>=0, [0:n+i] for i<0
00631                    *   [i:] ==> [i:n-1] for i>=0, [i+n:n-1] for i<0
00632                    * This will allow: [:-3] to index all but last 3, etc.
00633                    * Also consider cases with a negative increment:
00634                    *   [::-1] = [n-1,n-2,...0] = [n-1:0:-1]
00635                    *   [:i:-1] = [n-1,n-2,..i] = [n-1:i:-1]
00636                    *   [i::-1] = [i,i-1,...0] = [i:0:-1] 
00637                    */
00638                   SLang_Array_Type *new_at;
00639                   SLindex_Type first_index, last_index;
00640                   SLindex_Type delta = r->delta;
00641                   SLindex_Type n;
00642 
00643                   if (num_indices == 1)/* could be index array */
00644                     n = (SLindex_Type)at_to_index->num_elements;
00645                   else
00646                     n = at_to_index->dims[i];
00647 
00648                   if (r->has_first_index)
00649                     {
00650                        /* Case 3 */
00651                        first_index = r->first_index;
00652                        if (first_index < 0) first_index += n;
00653                        if (delta > 0) last_index = n-1; else last_index = 0;
00654                     }
00655                   else if (r->has_last_index)
00656                     {
00657                        /* case 2 */
00658                        if (delta > 0) first_index = 0; else first_index = n-1;
00659                        last_index = r->last_index;
00660                        if (last_index < 0)
00661                          last_index += n;
00662                     }
00663                   else
00664                     {
00665                        /* case 0 */
00666                        if (delta > 0)
00667                          {
00668                             first_index = 0;
00669                             last_index = n - 1;
00670                          }
00671                        else
00672                          {
00673                             first_index = n-1;
00674                             last_index = 0;
00675                          }
00676                     }
00677 
00678                   if (NULL == (new_at = inline_implicit_int_array (&first_index, &last_index, &delta)))
00679                     goto return_error;
00680              
00681                   SLang_free_array (at);
00682                   obj->v.array_val = new_at;
00683                }
00684           }
00685         if (num_indices == 1)
00686           {
00687              *is_index_array = 1;
00688              return 0;
00689           }
00690      }
00691    return 0;
00692 
00693    return_error:
00694    free_index_objects (index_objs, num_indices);
00695    return -1;
00696 }
00697 
00698 static void do_index_error (SLindex_Type i, SLindex_Type indx, SLindex_Type dim)
00699 {
00700    SLang_verror (SL_Index_Error, "Array index %u (value=%ld) out of allowed range 0<=index<%ld",
00701                  i, (long)indx, (long)dim);
00702 }
00703 
00704 static int
00705 transfer_n_elements (SLang_Array_Type *at, VOID_STAR dest_data, VOID_STAR src_data,
00706                      size_t sizeof_type, SLuindex_Type n, int is_ptr)
00707 {
00708    SLtype data_type;
00709    SLang_Class_Type *cl;
00710 
00711    if (is_ptr == 0)
00712      {
00713         SLMEMCPY ((char *) dest_data, (char *)src_data, n * sizeof_type);
00714         return 0;
00715      }
00716 
00717    data_type = at->data_type;
00718    cl = at->cl;
00719 
00720    while (n != 0)
00721      {
00722         if (*(VOID_STAR *)dest_data != NULL)
00723           {
00724              (*cl->cl_destroy) (data_type, dest_data);
00725              *(VOID_STAR *) dest_data = NULL;
00726           }
00727 
00728         if (*(VOID_STAR *) src_data == NULL)
00729           *(VOID_STAR *) dest_data = NULL;
00730         else
00731           {
00732              if (-1 == (*cl->cl_acopy) (data_type, src_data, dest_data))
00733                /* No need to destroy anything */
00734                return -1;
00735           }
00736 
00737         src_data = (VOID_STAR) ((char *)src_data + sizeof_type);
00738         dest_data = (VOID_STAR) ((char *)dest_data + sizeof_type);
00739 
00740         n--;
00741      }
00742 
00743    return 0;
00744 }
00745 
00746 _INLINE_
00747 int
00748 _pSLarray_aget_transfer_elem (SLang_Array_Type *at, SLindex_Type *indices,
00749                              VOID_STAR new_data, size_t sizeof_type, int is_ptr)
00750 {
00751    VOID_STAR at_data;
00752 
00753    /* Since 1 element is being transferred, there is no need to coerce
00754     * the array to linear.
00755     */
00756    if (NULL == (at_data = get_data_addr (at, indices)))
00757      return -1;
00758 
00759    if (is_ptr == 0)
00760      {
00761         memcpy ((char *) new_data, (char *)at_data, sizeof_type);
00762         return 0;
00763      }
00764 
00765    return transfer_n_elements (at, new_data, at_data, sizeof_type, 1, is_ptr);
00766 }
00767 
00768 /* Here the ind_at index-array is an n-d array of indices.  This function
00769  * creates an n-d array of made up of values of 'at' at the locations
00770  * specified by the indices.  The result is pushed.
00771  */
00772 static int
00773 aget_from_index_array (SLang_Array_Type *at,
00774                        SLang_Array_Type *ind_at)
00775 {
00776    SLang_Array_Type *new_at;
00777    SLindex_Type *indices, *indices_max, num_elements;
00778    unsigned char *new_data, *src_data;
00779    size_t sizeof_type;
00780    int is_ptr;
00781    
00782    if (-1 == coerse_array_to_linear (at))
00783      return -1;
00784 
00785    if (-1 == coerse_array_to_linear (ind_at))
00786      return -1;
00787 
00788    if (NULL == (new_at = SLang_create_array (at->data_type, 0, NULL, ind_at->dims, ind_at->num_dims)))
00789      return -1;
00790 
00791    /* Since the index array is linear, I can address it directly */
00792    indices = (SLindex_Type *) ind_at->data;
00793    indices_max = indices + ind_at->num_elements;
00794 
00795    src_data = (unsigned char *) at->data;
00796    new_data = (unsigned char *) new_at->data;
00797    num_elements = (SLindex_Type) at->num_elements;
00798    sizeof_type = new_at->sizeof_type;
00799    is_ptr = (new_at->flags & SLARR_DATA_VALUE_IS_POINTER);
00800 
00801    while (indices < indices_max)
00802      {
00803         size_t offset;
00804         SLindex_Type i = *indices;
00805 
00806         if (i < 0) 
00807           {
00808              i += num_elements;
00809              if (i < 0)
00810                i = num_elements;
00811           }
00812         if (i >= num_elements)
00813           {
00814              SLang_set_error (SL_Index_Error);
00815              SLang_free_array (new_at);
00816              return -1;
00817           }
00818 
00819         offset = sizeof_type * (SLuindex_Type)i;
00820         if (-1 == transfer_n_elements (at, (VOID_STAR) new_data,
00821                                        (VOID_STAR) (src_data + offset),
00822                                        sizeof_type, 1, is_ptr))
00823           {
00824              SLang_free_array (new_at);
00825              return -1;
00826           }
00827 
00828         new_data += sizeof_type;
00829         indices++;
00830      }
00831 
00832    return SLang_push_array (new_at, 1);
00833 }
00834 
00835 /* This is extremely ugly.  It is due to the fact that the index_objects
00836  * may contain ranges.  This is a utility function for the aget/aput
00837  * routines
00838  */
00839 static int
00840 convert_nasty_index_objs (SLang_Array_Type *at,
00841                           SLang_Object_Type *index_objs,
00842                           unsigned int num_indices,
00843                           SLindex_Type **index_data,
00844                           SLindex_Type *range_buf, SLindex_Type *range_delta_buf,
00845                           SLindex_Type *max_dims,
00846                           unsigned int *num_elements,
00847                           int *is_array, int is_dim_array[SLARRAY_MAX_DIMS])
00848 {
00849    unsigned int i, total_num_elements;
00850    SLang_Array_Type *ind_at;
00851 
00852    if (num_indices != at->num_dims)
00853      {
00854         SLang_verror (SL_INVALID_PARM, "Array requires %u indices", at->num_dims);
00855         return -1;
00856      }
00857 
00858    *is_array = 0;
00859    total_num_elements = 1;
00860    for (i = 0; i < num_indices; i++)
00861      {
00862         SLang_Object_Type *obj = index_objs + i;
00863         range_delta_buf [i] = 0;
00864 
00865         if (obj->data_type == SLANG_ARRAY_INDEX_TYPE)
00866           {
00867              range_buf [i] = obj->v.index_val;
00868              max_dims [i] = 1;
00869              index_data[i] = range_buf + i;
00870              is_dim_array[i] = 0;
00871           }
00872 #if SLANG_ARRAY_INDEX_TYPE != SLANG_INT_TYPE
00873         else if (obj->data_type == SLANG_INT_TYPE)
00874           {
00875              range_buf [i] = obj->v.int_val;
00876              max_dims [i] = 1;
00877              index_data[i] = range_buf + i;
00878              is_dim_array[i] = 0;
00879           }
00880 #endif
00881         else
00882           {
00883              *is_array = 1;
00884              is_dim_array[i] = 1;
00885              ind_at = obj->v.array_val;
00886 
00887              if (ind_at->flags & SLARR_DATA_VALUE_IS_RANGE)
00888                {
00889                   SLarray_Range_Array_Type *r;
00890 
00891                   r = (SLarray_Range_Array_Type *) ind_at->data;
00892                   range_buf[i] = r->first_index;
00893                   range_delta_buf [i] = r->delta;
00894                   max_dims[i] = (SLindex_Type) ind_at->num_elements;
00895                }
00896              else
00897                {
00898                   index_data [i] = (SLindex_Type *) ind_at->data;
00899                   max_dims[i] = (SLindex_Type) ind_at->num_elements;
00900                }
00901           }
00902 
00903         total_num_elements = total_num_elements * max_dims[i];
00904      }
00905 
00906    *num_elements = total_num_elements;
00907    return 0;
00908 }
00909 
00910 /* This routine pushes a 1-d vector of values from 'at' indexed by
00911  * the objects 'index_objs'.  These objects can either be integers or
00912  * 1-d integer arrays.  The fact that the 1-d arrays can be ranges
00913  * makes this look ugly.
00914  */
00915 static int
00916 aget_from_indices (SLang_Array_Type *at,
00917                    SLang_Object_Type *index_objs, unsigned int num_indices)
00918 {
00919    SLindex_Type *index_data [SLARRAY_MAX_DIMS];
00920    SLindex_Type range_buf [SLARRAY_MAX_DIMS];
00921    SLindex_Type range_delta_buf [SLARRAY_MAX_DIMS];
00922    SLindex_Type max_dims [SLARRAY_MAX_DIMS];
00923    unsigned int i, num_elements;
00924    SLang_Array_Type *new_at;
00925    SLindex_Type map_indices[SLARRAY_MAX_DIMS];
00926    SLindex_Type indices [SLARRAY_MAX_DIMS];
00927    SLindex_Type *at_dims;
00928    size_t sizeof_type;
00929    int is_ptr, ret, is_array;
00930    char *new_data;
00931    SLang_Class_Type *cl;
00932    int is_dim_array[SLARRAY_MAX_DIMS];
00933 
00934    if (-1 == convert_nasty_index_objs (at, index_objs, num_indices,
00935                                        index_data, range_buf, range_delta_buf,
00936                                        max_dims, &num_elements, &is_array,
00937                                        is_dim_array))
00938      return -1;
00939 
00940    is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER);
00941    sizeof_type = at->sizeof_type;
00942 
00943    cl = _pSLclass_get_class (at->data_type);
00944 
00945    if ((is_array == 0) && (num_elements == 1))
00946      {
00947         new_data = (char *)cl->cl_transfer_buf;
00948         memset (new_data, 0, sizeof_type);
00949         new_at = NULL;
00950      }
00951    else
00952      {
00953         SLindex_Type i_num_elements = (SLindex_Type)num_elements;
00954 
00955         new_at = SLang_create_array (at->data_type, 0, NULL, &i_num_elements, 1);
00956         if (NULL == new_at)
00957           return -1;
00958         if (num_elements == 0)
00959           return SLang_push_array (new_at, 1);
00960 
00961         new_data = (char *)new_at->data;
00962      }
00963    
00964    at_dims = at->dims;
00965    memset ((char *) map_indices, 0, sizeof(map_indices));
00966    while (1)
00967      {
00968         for (i = 0; i < num_indices; i++)
00969           {
00970              SLindex_Type j = map_indices[i];
00971              SLindex_Type indx;
00972 
00973              if (0 != range_delta_buf[i])
00974                indx = range_buf[i] + j * range_delta_buf[i];
00975              else
00976                indx = index_data [i][j];
00977 
00978              if (indx < 0)
00979                indx += at_dims[i];
00980 
00981              if ((indx < 0) || (indx >= at_dims[i]))
00982                {
00983                   do_index_error (i, indx, at_dims[i]);
00984                   SLang_free_array (new_at);
00985                   return -1;
00986                }
00987              indices[i] = indx;
00988           }
00989 
00990         if (-1 == _pSLarray_aget_transfer_elem (at, indices, (VOID_STAR)new_data, sizeof_type, is_ptr))
00991           {
00992              SLang_free_array (new_at);
00993              return -1;
00994           }
00995         new_data += sizeof_type;
00996         if (num_indices == 1) 
00997           {
00998              map_indices[0]++;
00999              if (map_indices[0] == max_dims[0])
01000                break;
01001           }
01002         else if (0 != _pSLarray_next_index (map_indices, max_dims, num_indices))
01003           break;        
01004      }
01005 
01006    if (new_at != NULL)
01007      {
01008         int num_dims = 0;
01009         /* Fixup dimensions on array */
01010         for (i = 0; i < num_indices; i++)
01011           {
01012              if (is_dim_array[i]) /* was: (max_dims[i] > 1) */
01013                {
01014                   new_at->dims[num_dims] = max_dims[i];
01015                   num_dims++;
01016                }
01017           }
01018 
01019         if (num_dims != 0) new_at->num_dims = num_dims;
01020         return SLang_push_array (new_at, 1);
01021      }
01022 
01023    /* Here new_data is a whole new copy, so free it after the push */
01024    new_data -= sizeof_type;
01025    if (is_ptr && (*(VOID_STAR *)new_data == NULL))
01026      ret = SLang_push_null ();
01027    else
01028      {
01029         ret = (*cl->cl_apush) (at->data_type, (VOID_STAR)new_data);
01030         (*cl->cl_adestroy) (at->data_type, (VOID_STAR)new_data);
01031      }
01032 
01033    return ret;
01034 }
01035 
01036 static int push_string_as_array (unsigned char *s, unsigned int len)
01037 {
01038    SLindex_Type ilen;
01039    SLang_Array_Type *at;
01040 
01041    ilen = (SLindex_Type) len;
01042 
01043    at = SLang_create_array (SLANG_UCHAR_TYPE, 0, NULL, &ilen, 1);
01044    if (at == NULL)
01045      return -1;
01046 
01047    memcpy ((char *)at->data, (char *)s, len);
01048    return SLang_push_array (at, 1);
01049 }
01050 
01051 static int pop_array_as_string (char **sp)
01052 {
01053    SLang_Array_Type *at;
01054    int ret;
01055 
01056    *sp = NULL;
01057 
01058    if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
01059      return -1;
01060 
01061    ret = 0;
01062 
01063    if (NULL == (*sp = SLang_create_nslstring ((char *) at->data, at->num_elements)))
01064      ret = -1;
01065 
01066    SLang_free_array (at);
01067    return ret;
01068 }
01069 
01070 static int pop_array_as_bstring (SLang_BString_Type **bs)
01071 {
01072    SLang_Array_Type *at;
01073    int ret;
01074 
01075    *bs = NULL;
01076 
01077    if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE))
01078      return -1;
01079 
01080    ret = 0;
01081 
01082    if (NULL == (*bs = SLbstring_create ((unsigned char *) at->data, at->num_elements)))
01083      ret = -1;
01084 
01085    SLang_free_array (at);
01086    return ret;
01087 }
01088 
01089 static int aget_from_array (unsigned int num_indices)
01090 {
01091    SLang_Array_Type *at;
01092    SLang_Object_Type index_objs [SLARRAY_MAX_DIMS];
01093    int ret;
01094    int is_index_array;
01095    unsigned int i;
01096 
01097    if (num_indices > SLARRAY_MAX_DIMS)
01098      {
01099         SLang_verror (SL_INVALID_PARM, "Number of dims must be less than %d", SLARRAY_MAX_DIMS);
01100         return -1;
01101      }
01102 
01103    if (-1 == pop_array (&at, 1))
01104      return -1;
01105 
01106    if (-1 == pop_indices (at, index_objs, num_indices, &is_index_array))
01107      {
01108         SLang_free_array (at);
01109         return -1;
01110      }
01111 
01112    if (is_index_array == 0)
01113      {
01114 #if SLANG_OPTIMIZE_FOR_SPEED
01115         if ((num_indices == 1) && (index_objs[0].data_type == SLANG_INT_TYPE)
01116             && (0 == (at->flags & (SLARR_DATA_VALUE_IS_RANGE|SLARR_DATA_VALUE_IS_POINTER)))
01117             && (1 == at->num_dims)
01118             && (at->data != NULL))
01119           {
01120              SLindex_Type ofs = index_objs[0].v.int_val;
01121              if (ofs < 0) ofs += at->dims[0];
01122              if ((ofs >= at->dims[0]) || (ofs < 0))
01123                ret = aget_from_indices (at, index_objs, num_indices);
01124              else switch (at->data_type)
01125                {
01126                 case SLANG_CHAR_TYPE:
01127                   ret = SLclass_push_char_obj (SLANG_CHAR_TYPE, *((char *)at->data + ofs));
01128                   break;
01129                 case SLANG_INT_TYPE:
01130                   ret = SLclass_push_int_obj (SLANG_INT_TYPE, *((int *)at->data + ofs));
01131                   break;
01132 #if SLANG_HAS_FLOAT
01133                 case SLANG_DOUBLE_TYPE:
01134                   ret = SLclass_push_double_obj (SLANG_DOUBLE_TYPE, *((double *)at->data + ofs));
01135                   break;
01136 #endif
01137                 default:
01138                   ret = aget_from_indices (at, index_objs, num_indices);
01139                }
01140           }
01141         else
01142 #endif
01143         ret = aget_from_indices (at, index_objs, num_indices);
01144      }
01145    else
01146      ret = aget_from_index_array (at, index_objs[0].v.array_val);
01147 
01148    SLang_free_array (at);
01149    for (i = 0; i < num_indices; i++)
01150      SLang_free_object (index_objs + i);
01151 
01152    return ret;
01153 }
01154 
01155 static int push_string_element (SLtype type, unsigned char *s, unsigned int len)
01156 {
01157    int i;
01158 
01159    if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE)
01160      {
01161         char *str;
01162 
01163         /* The indices are array values.  So, do this: */
01164         if (-1 == push_string_as_array (s, len))
01165           return -1;
01166 
01167         if (-1 == aget_from_array (1))
01168           return -1;
01169 
01170         if (type == SLANG_BSTRING_TYPE)
01171           {
01172              SLang_BString_Type *bs;
01173              int ret;
01174 
01175              if (-1 == pop_array_as_bstring (&bs))
01176                return -1;
01177 
01178              ret = SLang_push_bstring (bs);
01179              SLbstring_free (bs);
01180              return ret;
01181           }
01182 
01183         if (-1 == pop_array_as_string (&str))
01184           return -1;
01185         return _pSLang_push_slstring (str);   /* frees s upon error */
01186      }
01187 
01188    if (-1 == SLang_pop_integer (&i))
01189      return -1;
01190 
01191    if (i < 0) i = i + (int)len;
01192    if ((unsigned int) i > len)
01193      i = len;                          /* get \0 character --- bstrings include it as well */
01194 
01195    return SLang_push_uchar (s[(unsigned int)i]);
01196 }
01197 
01198 /* ARRAY[i, j, k] generates code: __args i j ...k ARRAY __aput/__aget
01199  * Here i, j, ... k may be a mixture of integers and 1-d arrays, or
01200  * a single array of indices.  The index array is generated by the
01201  * 'where' function.
01202  *
01203  * If ARRAY is of type DataType, then this function will create an array of
01204  * the appropriate type.  In that case, the indices i, j, ..., k must be
01205  * integers.
01206  */
01207 int _pSLarray_aget1 (unsigned int num_indices)
01208 {
01209    int type;
01210    int (*aget_fun) (SLtype, unsigned int);
01211 
01212    type = SLang_peek_at_stack ();
01213    switch (type)
01214      {
01215       case -1:
01216         return -1;                     /* stack underflow */
01217 
01218       case SLANG_DATATYPE_TYPE:
01219         return push_create_new_array (num_indices);
01220 
01221       case SLANG_BSTRING_TYPE:
01222         if (1 == num_indices)
01223           {
01224              SLang_BString_Type *bs;
01225              int ret;
01226              unsigned int len;
01227              unsigned char *s;
01228 
01229              if (-1 == SLang_pop_bstring (&bs))
01230                return -1;
01231 
01232              if (NULL == (s = SLbstring_get_pointer (bs, &len)))
01233                ret = -1;
01234              else
01235                ret = push_string_element (type, s, len);
01236 
01237              SLbstring_free (bs);
01238              return ret;
01239           }
01240         break;
01241 
01242       case SLANG_STRING_TYPE:
01243         if (1 == num_indices)
01244           {
01245              char *s;
01246              int ret;
01247 
01248              if (-1 == SLang_pop_slstring (&s))
01249                return -1;
01250 
01251              ret = push_string_element (type, (unsigned char *)s, _pSLstring_bytelen (s));
01252              _pSLang_free_slstring (s);
01253              return ret;
01254           }
01255         break;
01256 
01257       case SLANG_ARRAY_TYPE:
01258         break;
01259 
01260       case SLANG_ASSOC_TYPE:
01261         return _pSLassoc_aget (type, num_indices);
01262 
01263       default:
01264         aget_fun = _pSLclass_get_class (type)->cl_aget;
01265         if (NULL != aget_fun)
01266           return (*aget_fun) (type, num_indices);
01267      }
01268 
01269    return aget_from_array (num_indices);
01270 }
01271 
01272 int _pSLarray_aget (void)
01273 {
01274    return _pSLarray_aget1 ((unsigned int)(SLang_Num_Function_Args-1));
01275 }
01276 
01277 
01278 
01279 _INLINE_ int
01280 _pSLarray_aput_transfer_elem (SLang_Array_Type *at, SLindex_Type *indices,
01281                              VOID_STAR data_to_put, size_t sizeof_type, int is_ptr)
01282 {
01283    VOID_STAR at_data;
01284 
01285    /* 
01286     * A range array is not allowed here.  I should add a check for it.  At
01287     * the moment, one will not get here.
01288     */
01289    if (NULL == (at_data = get_data_addr (at, indices)))
01290      return -1;
01291 
01292    if (is_ptr == 0)
01293      {
01294         memcpy ((char *) at_data, (char *)data_to_put, sizeof_type);
01295         return 0;
01296      }
01297 
01298    return transfer_n_elements (at, at_data, data_to_put, sizeof_type, 1, is_ptr);
01299 }
01300 
01301 static int
01302 aput_get_data_to_put (SLang_Class_Type *cl, unsigned int num_elements, int allow_array,
01303                        SLang_Array_Type **at_ptr, char **data_to_put, SLuindex_Type *data_increment)
01304 {
01305    SLtype data_type;
01306    int type;
01307    SLang_Array_Type *at;
01308    
01309    *at_ptr = NULL;
01310 
01311    data_type = cl->cl_data_type;
01312    type = SLang_peek_at_stack ();
01313 
01314    if ((SLtype)type != data_type)
01315      {
01316         if ((type != SLANG_NULL_TYPE)
01317             || ((cl->cl_class_type != SLANG_CLASS_TYPE_PTR)
01318                 && (cl->cl_class_type != SLANG_CLASS_TYPE_MMT)))
01319           {
01320              if (-1 == SLclass_typecast (data_type, 1, allow_array))
01321                return -1;
01322           }
01323         else
01324           {
01325              /* This bit of code allows, e.g., a[10] = NULL; */
01326              *data_increment = 0;
01327              *data_to_put = (char *) cl->cl_transfer_buf;
01328              *((char **)cl->cl_transfer_buf) = NULL;
01329              return SLdo_pop ();
01330           }
01331      }
01332 
01333    if (allow_array
01334        && (data_type != SLANG_ARRAY_TYPE)
01335        && (data_type != SLANG_ANY_TYPE)
01336        && (SLANG_ARRAY_TYPE == SLang_peek_at_stack ()))
01337      {
01338         if (-1 == SLang_pop_array (&at, 0))
01339           return -1;
01340 
01341         if ((at->num_elements != num_elements)
01342 #if 0
01343             || (at->num_dims != 1)
01344 #endif
01345             )
01346           {
01347              SLang_verror (SL_Index_Error, "Array size is inappropriate for use with index-array");
01348              SLang_free_array (at);
01349              return -1;
01350           }
01351 
01352         *data_to_put = (char *) at->data;
01353         *data_increment = at->sizeof_type;
01354         *at_ptr = at;
01355         return 0;
01356      }
01357 
01358    *data_increment = 0;
01359    *data_to_put = (char *) cl->cl_transfer_buf;
01360 
01361    if (-1 == (*cl->cl_apop)(data_type, (VOID_STAR) *data_to_put))
01362      return -1;
01363 
01364    return 0;
01365 }
01366 
01367 static int
01368 aput_from_indices (SLang_Array_Type *at,
01369                    SLang_Object_Type *index_objs, unsigned int num_indices)
01370 {
01371    SLindex_Type *index_data [SLARRAY_MAX_DIMS];
01372    SLindex_Type range_buf [SLARRAY_MAX_DIMS];
01373    SLindex_Type range_delta_buf [SLARRAY_MAX_DIMS];
01374    SLindex_Type max_dims [SLARRAY_MAX_DIMS];
01375    SLindex_Type *at_dims;
01376    unsigned int i, num_elements;
01377    SLa