int _pSLclass_obj_eqs (SLang_Object_Type *a, SLang_Object_Type *b)
{
   SLang_Class_Type *a_cl, *b_cl;
   VOID_STAR pa, pb;
   int (*eqs)(SLtype, VOID_STAR, SLtype, VOID_STAR);
   int status;

   a_cl = _pSLclass_get_class (a->o_data_type);
   b_cl = _pSLclass_get_class (b->o_data_type);

   pa = _pSLclass_get_ptr_to_value (a_cl, a);
   pb = _pSLclass_get_ptr_to_value (b_cl, b);

   if ((pa == NULL) || (pb == NULL))
     return -1;

   if ((NULL == (eqs = a_cl->cl_eqs))
       && (NULL == (eqs = b_cl->cl_eqs)))
     return do_default_eqs (a_cl, pa, b_cl, pb);

   status = push_eqs_comparison (a, b);
   if (status != 0)
     return status;

   status = (*eqs) (a->o_data_type, pa, b->o_data_type, pb);
   pop_eqs_comparison ();
   return status;
}
int SLclass_add_binary_op (SLtype a, SLtype b,
			   int (*f) (int,
				     SLtype, VOID_STAR, unsigned int,
				     SLtype, VOID_STAR, unsigned int,
				     VOID_STAR),
			   int (*r) (int, SLtype, SLtype, SLtype *))
{
   SL_OOBinary_Type *ab;
   SLang_Class_Type *cl;

   if ((f == NULL) || (r == NULL)
       || ((a == SLANG_VOID_TYPE) && (b == SLANG_VOID_TYPE)))
     {
	_pSLang_verror (SL_INVALID_PARM, "SLclass_add_binary_op");
	return -1;
     }

   if (NULL == (ab = (SL_OOBinary_Type *) SLmalloc (sizeof(SL_OOBinary_Type))))
     return -1;

   ab->binary_function = f;
   ab->binary_result = r;
   
   if (a == SLANG_VOID_TYPE)
     {
	cl = _pSLclass_get_class (b);
	ab->data_type = a;
	ab->next = NULL;
	cl->cl_void_binary_this = ab;
     }
   else if (b == SLANG_VOID_TYPE)
     {
	cl = _pSLclass_get_class (a);
	ab->data_type = b;
	ab->next = NULL;
	cl->cl_this_binary_void = ab;
     }
   else
     {
	cl = _pSLclass_get_class (a);
	ab->next = cl->cl_binary_ops;
	ab->data_type = b;
	cl->cl_binary_ops = ab;
     }

   if ((a != SLANG_ARRAY_TYPE)
       && (b != SLANG_ARRAY_TYPE))
     {
	if ((-1 == _pSLarray_add_bin_op (a))
	    || (-1 == _pSLarray_add_bin_op (b)))
	  return -1;
     }

   return 0;
}
Esempio n. 3
0
/* AnyType */
int _pSLanytype_typecast (SLtype a_type, VOID_STAR ap, unsigned int na,
			 SLtype b_type, VOID_STAR bp)
{
   SLang_Class_Type *cl;
   SLang_Any_Type **any;
   unsigned int i;
   unsigned int sizeof_type;

   (void) b_type;

   any = (SLang_Any_Type **) bp;
   
   cl = _pSLclass_get_class (a_type);
   sizeof_type = cl->cl_sizeof_type;

   for (i = 0; i < na; i++)
     {
	if ((-1 == (*cl->cl_apush) (a_type, ap))
	    || (-1 == SLang_pop_anytype (&any[i])))
	  {
	     while (i != 0)
	       {
		  i--;
		  SLang_free_anytype (any[i]);
		  any[i] = NULL;
	       }
	     return -1;
	  }
	ap = (VOID_STAR)((char *)ap + sizeof_type);
     }

   return 1;
}
SLFUTURE_CONST char *SLclass_get_datatype_name (SLtype stype)
{
   SLang_Class_Type *cl;

   cl = _pSLclass_get_class (stype);
   return cl->cl_name;
}
int _pSLclass_is_same_obj (SLang_Object_Type *a, SLang_Object_Type *b)
{
   SLang_Class_Type *cl;
   unsigned int sizeof_type;

   if (a->o_data_type != b->o_data_type)
     return 0;

   cl = _pSLclass_get_class (a->o_data_type);
   sizeof_type = cl->cl_sizeof_type;

   switch (cl->cl_class_type)
     {
      case SLANG_CLASS_TYPE_MMT:
      case SLANG_CLASS_TYPE_PTR:
	return (a->v.ptr_val == b->v.ptr_val);

      case SLANG_CLASS_TYPE_SCALAR:
	return !memcmp (&a->v, &b->v, sizeof_type);
	
      case SLANG_CLASS_TYPE_VECTOR:
	return !memcmp (a->v.ptr_val, b->v.ptr_val, sizeof_type);
     }
   return 0;
}
static int vector_apop (SLtype type, VOID_STAR ptr)
{
   SLang_Class_Type *cl;

   cl = _pSLclass_get_class (type);
   return (*cl->cl_pop)(type, (VOID_STAR) &ptr);
}
Esempio n. 7
0
static int length_cmd (void)
{
   SLang_Class_Type *cl;
   SLang_Object_Type obj;
   VOID_STAR p;
   unsigned int length;
   int len;

   if (-1 == SLang_pop (&obj))
     return -1;

   cl = _pSLclass_get_class (obj.o_data_type);
   p = _pSLclass_get_ptr_to_value (cl, &obj);

   len = 1;
   if (cl->cl_length != NULL)
     {
	if (0 == (*cl->cl_length)(obj.o_data_type, p, &length))
	  len = (int) length;
	else
	  len = -1;
     }

   SLang_free_object (&obj);
   return len;
}
int SLclass_create_synonym (SLFUTURE_CONST char *name, SLtype type)
{
   if (NULL == _pSLclass_get_class (type))
     return -1;

   return register_new_datatype (name, type);
}
Esempio n. 9
0
static int class_id_intrinsic (void)
{
   SLtype type;

   if (-1 == SLang_pop_datatype (&type))
     return -1;
   return _pSLclass_get_class (type)->cl_data_type;
}
int SLang_push_datatype (SLtype data_type)
{
   /* This data type could be a copy of another type, e.g., short and
    * int if they are the same size (Int16 == Short).  So, make sure
    * we push the original and not the copy. 
    */
   data_type = _pSLclass_get_class (data_type)->cl_data_type;
   return SLclass_push_int_obj (SLANG_DATATYPE_TYPE, data_type);
}
static int default_acopy (SLtype type, VOID_STAR from, VOID_STAR to)
{
   SLang_Class_Type *cl;

   cl = _pSLclass_get_class (type);
   if (-1 == (*cl->cl_apush) (type, from))
     return -1;
   return (*cl->cl_apop) (type, to);
}
int SLclass_add_math_op (SLtype type,
			 int (*handler)(int,
					SLtype, VOID_STAR, unsigned int,
					VOID_STAR),
			 int (*result) (int, SLtype, SLtype *))
{
   SLang_Class_Type *cl = _pSLclass_get_class (type);

   cl->cl_math_op = handler;
   cl->cl_math_op_result_type = result;
   return 0;
}
Esempio n. 13
0
static void datatype_intrinsic (SLtype *t)
{
   SLang_Class_Type *cl;

   if (0 == SLclass_is_class_defined (*t))
     {
	(void) SLang_push_null ();
	return;
     }

   cl = _pSLclass_get_class (*t);
   (void) SLang_push_datatype (cl->cl_data_type);
}
int (*_pSLclass_get_unary_fun (int op,
			      SLang_Class_Type *a_cl,
			      SLang_Class_Type **b_cl,
			      int utype))
(int, SLtype, VOID_STAR, unsigned int, VOID_STAR)
{
   int (*f)(int, SLtype, VOID_STAR, unsigned int, VOID_STAR);
   int (*r)(int, SLtype, SLtype *);
   SLtype a;
   SLtype b;

   switch (utype)
     {
      case SLANG_BC_ARITH_UNARY:
      case SLANG_BC_UNARY:
	f = a_cl->cl_unary_op;
	r = a_cl->cl_unary_op_result_type;
	break;

      case SLANG_BC_MATH_UNARY:
	f = a_cl->cl_math_op;
	r = a_cl->cl_math_op_result_type;
	break;

      case SLANG_BC_APP_UNARY:
	f = a_cl->cl_app_unary_op;
	r = a_cl->cl_app_unary_op_result_type;
	break;

      default:
	f = NULL;
	r = NULL;
     }

   a = a_cl->cl_data_type;
   if ((f != NULL) && (r != NULL) && (1 == (*r) (op, a, &b)))
     {
	if (a == b)
	  *b_cl = a_cl;
	else
	  *b_cl = _pSLclass_get_class (b);
	return f;
     }

   _pSLang_verror (SL_TYPE_MISMATCH, "undefined unary operation/function on %s",
		 a_cl->cl_name);

   *b_cl = NULL;

   return NULL;
}
Esempio n. 15
0
static int istruct_sput (SLtype type, SLFUTURE_CONST char *name)
{
   SLang_IStruct_Field_Type *f;
   VOID_STAR addr;
   SLang_Class_Type *cl;

   if (NULL == (f = istruct_pop_field (name, 1, &addr)))
     return -1;

   type = f->type;
   cl = _pSLclass_get_class (type);

   return (*cl->cl_pop) (type, addr);
}
static int
scalar_vector_bin_op (int op,
		      SLtype a_type, VOID_STAR ap, unsigned int na,
		      SLtype b_type, VOID_STAR bp, unsigned int nb,
		      VOID_STAR cp)
{
   char *c;
   char *a, *b;
   unsigned int da, db;
   unsigned int n, n_max;
   unsigned int data_type_len;
   SLang_Class_Type *cl;

   (void) b_type;
   cl = _pSLclass_get_class (a_type);

   data_type_len = cl->cl_sizeof_type;

   a = (char *) ap;
   b = (char *) bp;
   c = (char *) cp;

   if (na == 1) da = 0; else da = data_type_len;
   if (nb == 1) db = 0; else db = data_type_len;
   if (na > nb) n_max = na; else n_max = nb;

   switch (op)
     {
      default:
	return 0;

      case SLANG_NE:
	for (n = 0; n < n_max; n++)
	  {
	     c[n] = (0 != SLMEMCMP(a, b, data_type_len));
	     a += da; b += db;
	  }
	break;

      case SLANG_EQ:
	for (n = 0; n < n_max; n++)
	  {
	     c[n] = (0 == SLMEMCMP(a, b, data_type_len));
	     a += da; b += db;
	  }
	break;
     }
   return 1;
}
static int scalar_fwrite (SLtype type, FILE *fp, VOID_STAR ptr,
			 unsigned int desired, unsigned int *actual)
{
   unsigned int n;
   char *buf = (char *)ptr;
   size_t desired_bytes, actual_bytes;
   size_t size = _pSLclass_get_class (type)->cl_sizeof_type;

   desired_bytes = size * desired;
   actual_bytes = 0;

   while (desired_bytes)
     {
	int e;

	errno = 0;
	n = fwrite (buf, 1, desired_bytes, fp);

	actual_bytes += n;
	if (n == desired_bytes)
	  break;

	e = errno;
	desired_bytes -= n;
	buf += n;

	clearerr (fp);
#ifdef EINTR
	if ((e == EINTR)
	    && (0 == SLang_handle_interrupt ()))
	  continue;
#endif
	_pSLerrno_errno = e;

	/* Apparantly, the write can be interrupted returning a short item
	 * count but not set errno.
	 */
	if (n == 0)
	  break;
     }

   if (actual_bytes % size)
     {
	/* Sigh.  We failed to write out a full object. */
     }
   *actual = actual_bytes / size;
   return 0;
}
static int scalar_fread (SLtype type, FILE *fp, VOID_STAR ptr,
			 unsigned int desired, unsigned int *actual)
{
   unsigned int n;
   char *buf = (char *)ptr;
   size_t desired_bytes, actual_bytes;
   size_t size = _pSLclass_get_class (type)->cl_sizeof_type;

   desired_bytes = size * desired;
   actual_bytes = 0;

   while (desired_bytes)
     {
	int e;

	errno = 0;
	n = fread (buf, 1, desired_bytes, fp);

	actual_bytes += n;
	if (n == desired_bytes)
	  break;

	e = errno;
	desired_bytes -= n;
	buf += n;

	clearerr (fp);
#ifdef EINTR
	if ((e == EINTR)
	    && (0 == SLang_handle_interrupt ()))
	  continue;
#endif
	_pSLerrno_errno = e;
	break;
     }

   if (actual_bytes % size)
     {
	/* Sigh.  We failed to read a full object. */
     }
   *actual = actual_bytes / size;
   return 0;
}
Esempio n. 19
0
static void assoc_get_values (SLang_Assoc_Array_Type *a)
{
   SLang_Array_Type *at;
   SLindex_Type num;
   char *dest_data;
   SLtype type;
   SLang_Class_Type *cl;
   unsigned int sizeof_type;
   _pSLAssoc_Array_Element_Type *e, *emax;

   /* Note: If support for threads is added, then we need to modify this
    * algorithm to prevent another thread from modifying the array.
    * However, that should be handled in inner_interp.
    */
   num = a->num_occupied - a->num_deleted;
   type = a->type;

   cl = _pSLclass_get_class (type);
   sizeof_type = cl->cl_sizeof_type;

   if (NULL == (at = SLang_create_array (type, 0, NULL, &num, 1)))
     return;

   dest_data = (char *)at->data;

   e = a->elements;
   emax = e + a->table_len;
   
   while (e < emax)
     {
	if ((e->key != NULL) && (e->key != Deleted_Key))
	  {
	     if (-1 == transfer_element (cl, (VOID_STAR) dest_data, &e->value))
	       {
		  SLang_free_array (at);
		  return;
	       }
	     dest_data += sizeof_type;
	  }
	e++;
     }
   (void) SLang_push_array (at, 1);
}
static int datatype_deref (SLtype type, VOID_STAR ptr)
{
   SLang_Class_Type *cl;
   int status;

   /* The parser generated code for this as if a function call were to be
    * made.  However, we are calling the deref object routine
    * instead of the function call.  So, I must simulate the function call.
    */
   if (-1 == _pSL_increment_frame_pointer ())
     return -1;

   type = (SLtype) *(int *) ptr;
   cl = _pSLclass_get_class (type);
   status = (*cl->cl_datatype_deref) (type);

   (void) _pSL_decrement_frame_pointer ();
   return status;
}
int SLclass_add_app_unary_op (SLtype type,
			      int (*f)(int,
				       SLtype, VOID_STAR, unsigned int,
				       VOID_STAR),
			      int (*r)(int, SLtype, SLtype *))
{
   SLang_Class_Type *cl;

   cl = _pSLclass_get_class (type);
   if ((f == NULL) || (r == NULL))
     {
	_pSLang_verror (SL_INVALID_PARM, "SLclass_add_app_unary_op");
	return -1;
     }

   cl->cl_app_unary_op = f;
   cl->cl_app_unary_op_result_type = r;

   return 0;
}
int _pSLclass_copy_class (SLtype to, SLtype from)
{
   SLang_Class_Type *cl, **clp;
   Class_Table_Type *t;

   cl = _pSLclass_get_class (from);
   if (NULL == (clp = alloc_class_slot (to, &t)))
     return -1;
   
   if (*clp != NULL)
     {
	_pSLang_verror (SL_APPLICATION_ERROR, "Class %d already exists", to);
	SLang_exit_error ("Application error: Fatal error");
     }
   add_class_to_slot (t, clp, cl);
#if SLANG_OPTIMIZE_FOR_SPEED
   _pSLang_set_class_info (to, cl);
#endif
   return 0;
}
Esempio n. 23
0
/* format object into a string and returns slstring */
char *_pSLstringize_object (SLang_Object_Type *obj) /*{{{*/
{
   SLang_Class_Type *cl;
   SLtype stype;
   VOID_STAR p;
   char *s, *s1;

   stype = obj->o_data_type;
   p = (VOID_STAR) &obj->v.ptr_val;

   cl = _pSLclass_get_class (stype);

   s = (*cl->cl_string) (stype, p);
   if (s != NULL)
     {
	s1 = SLang_create_slstring (s);
	SLfree (s);
	s = s1;
     }
   return s;
}
int (*_pSLclass_get_typecast (SLtype from, SLtype to, int is_implicit))
(SLtype, VOID_STAR, unsigned int,
 SLtype, VOID_STAR)
{
   SL_Typecast_Type *t;
   SLang_Class_Type *cl_from;

   cl_from = _pSLclass_get_class (from);

   t = cl_from->cl_typecast_funs;
   while (t != NULL)
     {
	if (t->data_type != to)
	  {
	     t = t->next;
	     continue;
	  }

	if (is_implicit && (t->allow_implicit == 0))
	  break;

	return t->typecast;
     }

   if (to == SLANG_ANY_TYPE)
     return &_pSLanytype_typecast;

   if ((is_implicit == 0)
       && (cl_from->cl_void_typecast != NULL))
     return cl_from->cl_void_typecast;

   _pSLang_verror (SL_TYPE_MISMATCH, "Unable to typecast %s to %s",
		 cl_from->cl_name,
		 SLclass_get_datatype_name (to));

   return NULL;
}
Esempio n. 25
0
int SLang_assign_to_ref (SLang_Ref_Type *ref, SLtype type, VOID_STAR v)
{
   SLang_Object_Type *stkptr;
   SLang_Class_Type *cl;
   
   cl = _pSLclass_get_class (type);

   /* Use apush since this function is passing ``array'' bytes rather than the
    * address of the data.  I need to somehow make this more consistent.  To
    * see what I mean, consider:
    * 
    *    double z[2];
    *    char *s = "silly";
    *    char bytes[10];  BAD--- Don't do this
    *    int i;
    * 
    *    SLang_assign_to_ref (ref, SLANG_INT_TYPE,    &i);
    *    SLang_assign_to_ref (ref, SLANG_STRING_TYPE, &s);
    *    SLang_assign_to_ref (ref, SLANG_COMPLEX_TYPE, z);
    * 
    * That is, all external routines that take a VOID_STAR argument need to
    * be documented such that how the function should be called with the
    * various class_types.
    */
   if (-1 == (*cl->cl_apush) (type, v))
     return -1;

   stkptr = _pSLang_get_run_stack_pointer ();
   if (0 == _pSLang_deref_assign (ref))
     return 0;

   if (stkptr != _pSLang_get_run_stack_pointer ())
     SLdo_pop ();

   return -1;
}
int SLclass_dup_object (SLtype type, VOID_STAR from, VOID_STAR to)
{
   SLang_Class_Type *cl = _pSLclass_get_class (type);
   return cl->cl_acopy (type, from, to);
}
Esempio n. 27
0
void _pSLunpack (char *format, SLang_BString_Type *bs)
{
   Format_Type ft;
   unsigned char *b;
   unsigned int len;
   unsigned int num_bytes;

   check_native_byte_order ();

   if (-1 == compute_size_for_format (format, &num_bytes))
     return;

   b = SLbstring_get_pointer (bs, &len);
   if (b == NULL)
     return;

   if (len < num_bytes)
     {
	_pSLang_verror (SL_INVALID_PARM,
		      "unpack format %s is too large for input string",
		      format);
	return;
     }

   while (1 == parse_a_format (&format, &ft))
     {
	char *str, *s;

	if (ft.repeat == 0)
	  continue;

	if (ft.data_type == 0)
	  {			       /* skip padding */
	     b += ft.repeat;
	     continue;
	  }

	if (ft.is_scalar)
	  {
	     SLang_Array_Type *at;
	     SLindex_Type dims;

	     if (ft.repeat == 1)
	       {
		  SLang_Class_Type *cl;

		  cl = _pSLclass_get_class (ft.data_type);
		  memcpy ((char *)cl->cl_transfer_buf, (char *)b, ft.sizeof_type);
		  if (ft.byteorder != NATIVE_ORDER)
		    byteswap (ft.byteorder, (unsigned char *)cl->cl_transfer_buf, ft.sizeof_type, 1);

		  if (-1 == (cl->cl_apush (ft.data_type, cl->cl_transfer_buf)))
		    return;
		  b += ft.sizeof_type;
		  continue;
	       }

	     dims = (SLindex_Type) ft.repeat;
	     at = SLang_create_array (ft.data_type, 0, NULL, &dims, 1);
	     if (at == NULL)
	       return;

	     num_bytes = ft.repeat * ft.sizeof_type;
	     memcpy ((char *)at->data, (char *)b, num_bytes);
	     if (ft.byteorder != NATIVE_ORDER)
	       byteswap (ft.byteorder, (unsigned char *)at->data, ft.sizeof_type, ft.repeat);

	     if (-1 == SLang_push_array (at, 1))
	       return;

	     b += num_bytes;
	     continue;
	  }
	
	/* string type: s, S, or Z */
	if (ft.format_type == 's')
	  len = ft.repeat;
	else
	  len = get_unpadded_strlen ((char *)b, ft.pad, ft.repeat);

	str = SLmalloc (len + 1);
	if (str == NULL)
	  return;
	memcpy ((char *) str, (char *)b, len);
	str [len] = 0;

	/* Avoid a bstring if possible */
	s = SLmemchr (str, 0, len);
	if (s == NULL)
	  {
	     if (-1 == SLang_push_malloced_string (str))
	       return;
	  }
	else
	  {
	     SLang_BString_Type *new_bs;

	     new_bs = SLbstring_create_malloced ((unsigned char *)str, len, 1);
	     if (new_bs == NULL)
	       return;

	     if (-1 == SLang_push_bstring (new_bs))
	       {
		  SLfree (str);
		  return;
	       }
	     SLbstring_free (new_bs);
	  }

	b += ft.repeat;
     }
}
Esempio n. 28
0
static void get_exception_info_intrinsic (void)
{
#define NUM_EXCEPT_FIELDS 8
   static SLFUTURE_CONST char *field_names[NUM_EXCEPT_FIELDS] =
     {
	"error", "descr", "file", "line", "function", "object", "message", "traceback"
     };
   SLtype field_types[NUM_EXCEPT_FIELDS];
   VOID_STAR field_values[NUM_EXCEPT_FIELDS];
   int err;
   SLCONST char *desc;
   SLCONST char *file;
   SLCONST char *function;
   SLCONST char *errmsg;
   SLCONST char *tbmsg;
   int linenum;

   err = _pSLerr_get_last_error ();
   if (err == 0)
     {
	(void) SLang_push_null ();
	return;
     }

   desc = SLerr_strerror (err);
   (void) _pSLerr_get_last_error_line_info (&file, &linenum, &function);

   field_types[0] = SLANG_INT_TYPE;
   field_values[0] = (VOID_STAR) &err;

   field_types[1] = SLANG_STRING_TYPE;
   field_values[1] = (VOID_STAR) &desc;

   field_types[2] = SLANG_STRING_TYPE;
   field_values[2] = (VOID_STAR) &file;

   field_types[3] = SLANG_INT_TYPE;
   field_values[3] = (VOID_STAR) &linenum;

   field_types[4] = SLANG_STRING_TYPE;
   field_values[4] = (VOID_STAR) &function;

   if ((Error_Context == NULL)
       || (Error_Context->object_was_thrown == 0))
     {
	char *null = NULL;
	field_types[5] = SLANG_NULL_TYPE;
	field_values[5] = (VOID_STAR) &null;
     }
   else
     {
	SLtype data_type = Error_Context->object_thrown.o_data_type;
	field_types[5] = data_type;
	field_values[5] = _pSLclass_get_ptr_to_value (_pSLclass_get_class (data_type),
						      &Error_Context->object_thrown);
     }
   errmsg = get_error_msg_from_queue  (_SLERR_MSG_ERROR);
   if ((errmsg == NULL) || (*errmsg == 0))
     errmsg = desc;
   field_types[6] = SLANG_STRING_TYPE;
   field_values[6] = (VOID_STAR) &errmsg;

   tbmsg = get_error_msg_from_queue  (_SLERR_MSG_TRACEBACK);
   field_types[7] = (tbmsg == NULL) ? SLANG_NULL_TYPE : SLANG_STRING_TYPE;
   field_values[7] = (VOID_STAR) &tbmsg;

   (void) SLstruct_create_struct (NUM_EXCEPT_FIELDS, field_names, field_types, field_values);
   if (errmsg != desc)
     SLang_free_slstring ((char *) errmsg);
   SLang_free_slstring ((char *)tbmsg);
}
Esempio n. 29
0
static int map_or_contract_array (SLCONST SLarray_Map_Type *c, int use_contraction,
				  int dim_specified, int *use_this_dim,
				  VOID_STAR clientdata)
{
   int k, use_all_dims;
   SLang_Array_Type *at, *new_at;
   SLindex_Type *old_dims;
   SLindex_Type old_dims_buf[SLARRAY_MAX_DIMS];
   SLindex_Type sub_dims[SLARRAY_MAX_DIMS];
   SLindex_Type tmp_dims[SLARRAY_MAX_DIMS];
   unsigned int i, j, old_num_dims, sub_num_dims;
   SLtype new_data_type, old_data_type;
   char *old_data, *new_data;
   SLindex_Type w[SLARRAY_MAX_DIMS], wk;
   size_t old_sizeof_type, new_sizeof_type;
   SLuindex_Type dims_k;
   int from_type;
   SLCONST SLarray_Map_Type *csave;
   SLarray_Map_Fun_Type *fmap;
   SLarray_Contract_Fun_Type *fcon;

   use_all_dims = 1;
   k = 0;
   if (dim_specified)
     {
	if (use_this_dim != NULL)
	  {
	     k = *use_this_dim;
	     use_all_dims = 0;
	  }
     }
   else if (SLang_Num_Function_Args == 2)
     {
	if (-1 == SLang_pop_integer (&k))
	  return -1;

	use_all_dims = 0;
     }

   if (-1 == (from_type = SLang_peek_at_stack1 ()))
     return -1;

   csave = c;
   while (c->f != NULL)
     {
	if (c->from_type == (SLtype) from_type)
	  break;
	c++;
     }

   /* Look for a more generic version */
   if (c->f != NULL)
     {
	if (-1 == SLang_pop_array_of_type (&at, c->typecast_to_type))
	  return -1;
     }
   else
     {
	/* Look for a wildcard match */
	c = csave;
	while (c->f != NULL)
	  {
	     if (c->from_type == SLANG_VOID_TYPE)
	       break;
	     c++;
	  }
	if (c->f == NULL)
	  {
	     _pSLang_verror (SL_TYPE_MISMATCH, "%s is not supported by this function", SLclass_get_datatype_name (from_type));
	     return -1;
	  }

	/* Found it. So, typecast it to appropriate type */
	if (c->typecast_to_type == SLANG_VOID_TYPE)
	  {
	     if (-1 == SLang_pop_array (&at, 1))
	       return -1;
	  }
	else if (-1 == SLang_pop_array_of_type (&at, c->typecast_to_type))
	  return -1;
     }

   old_data_type = at->data_type;
   if (SLANG_VOID_TYPE == (new_data_type = c->result_type))
     new_data_type = old_data_type;

   old_num_dims = at->num_dims;

   if (use_all_dims == 0)
     {
	if (k < 0)
	  k += old_num_dims;

	if ((k < 0) || (k >= (int)old_num_dims))
	  {
	     _pSLang_verror (SL_INVALID_PARM, "Dimension %d is invalid for a %d-d array",
			   k, old_num_dims);
	     SLang_free_array (at);
	     return -1;
	  }
	old_dims = at->dims;
     }
   else
     {
	old_dims = old_dims_buf;
	old_dims[0] = (SLindex_Type)at->num_elements;
	old_num_dims = 1;
     }

   fcon = (SLarray_Contract_Fun_Type *) c->f;
   fmap = c->f;

   if (use_contraction
       && (use_all_dims || (old_num_dims == 1)))
     {
	SLang_Class_Type *cl;
	VOID_STAR buf;
	int status = 0;

	cl = _pSLclass_get_class (new_data_type);
	buf = cl->cl_transfer_buf;
	if (at->num_elements == 0)
	  {
	     /* If there are no elements, the fcon may or may not
	      * compute a value.  So, clear the buffer
	      */
	     memset ((char *)buf, 0, cl->cl_sizeof_type);
	  }

	if ((-1 == (*fcon) (at->data, 1, at->num_elements, buf))
	    || (-1 == SLang_push_value (new_data_type, buf)))
	  status = -1;

	SLang_free_array (at);
	return status;
     }

   /* The offset for the index i_0,i_1,...i_{N-1} is
    * i_0*W_0 + i_1*W_1 + ... i_{N-1}*W{N-1}
    * where W_j = d_{j+1}d_{j+2}...d_{N-1}
    * and d_k is the number of elements of the kth dimension.
    *
    * For a specified value of k, we
    * So, summing over all elements in the kth dimension of the array
    * means using the set of offsets given by
    *
    *   i_k*W_k + sum(j!=k) i_j*W_j.
    *
    * So, we want to loop of all dimensions except for the kth using an
    * offset given by sum(j!=k)i_jW_j, and an increment W_k between elements.
    */

   wk = 1;
   i = old_num_dims;
   while (i != 0)
     {
	i--;
	w[i] = wk;
	wk *= old_dims[i];
     }
   wk = w[k];

   /* Now set up the sub array */
   j = 0;
   for (i = 0; i < old_num_dims; i++)
     {
	if (i == (unsigned int) k)
	  continue;

	sub_dims[j] = old_dims[i];
	w[j] = w[i];
	tmp_dims[j] = 0;
	j++;
     }
   sub_num_dims = old_num_dims - 1;

   if (use_contraction)
     new_at = SLang_create_array1 (new_data_type, 0, NULL, sub_dims, sub_num_dims, 1);
   else
     new_at = SLang_create_array1 (new_data_type, 0, NULL, old_dims, old_num_dims, 1);

   if (new_at == NULL)
     {
	SLang_free_array (at);
	return -1;
     }

   new_data = (char *)new_at->data;
   old_data = (char *)at->data;
   old_sizeof_type = at->sizeof_type;
   new_sizeof_type = new_at->sizeof_type;
   dims_k = old_dims[k] * wk;

   /* Skip this for cases such as sum(Double_Type[0,0], 1).  Otherwise,
    * (*fcon) will write to new_data, which has no length
    */
   if (new_at->num_elements) do
     {
	size_t offset = 0;
	int status;

	for (i = 0; i < sub_num_dims; i++)
	  offset += w[i] * tmp_dims[i];

	if (use_contraction)
	  {
	     status = (*fcon) ((VOID_STAR)(old_data + offset*old_sizeof_type), wk,
			       dims_k, (VOID_STAR) new_data);
	     new_data += new_sizeof_type;
	  }
	else
	  {
	     status = (*fmap) (old_data_type, (VOID_STAR) (old_data + offset*old_sizeof_type),
			       wk, dims_k,
			       new_data_type, (VOID_STAR) (new_data + offset*new_sizeof_type),
			       clientdata);
	  }

	if (status == -1)
	  {
	     SLang_free_array (new_at);
	     SLang_free_array (at);
	     return -1;
	  }
     }
   while (-1 != _pSLarray_next_index (tmp_dims, sub_dims, sub_num_dims));

   SLang_free_array (at);
   return SLang_push_array (new_at, 1);
}
static int
use_cmp_bin_op (int op,
		SLtype a_type, VOID_STAR ap, unsigned int na,
		SLtype b_type, VOID_STAR bp, unsigned int nb,
		VOID_STAR cp)
{
   int *c;
   char *a, *b;
   unsigned int da, db;
   unsigned int n, n_max;
   unsigned int data_type_len;
   SLang_Class_Type *cl;
   int (*cmp)(SLtype, VOID_STAR, VOID_STAR, int *);

   (void) b_type;
   cl = _pSLclass_get_class (a_type);
   cmp = cl->cl_cmp;
   data_type_len = cl->cl_sizeof_type;

   a = (char *) ap;
   b = (char *) bp;
   c = (int *) cp;

   if (na == 1) da = 0; else da = data_type_len;
   if (nb == 1) db = 0; else db = data_type_len;
   if (na > nb) n_max = na; else n_max = nb;

   switch (op)
     {
	int result;
	
      default:
	return 0;

      case SLANG_NE:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result != 0);
	     a += da; b += db;
	  }
	break;

      case SLANG_EQ:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result == 0);
	     a += da; b += db;
	  }
	break;

      case SLANG_GT:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result > 0);
	     a += da; b += db;
	  }
	break;
      case SLANG_GE:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result >= 0);
	     a += da; b += db;
	  }
	break;
      case SLANG_LT:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result < 0);
	     a += da; b += db;
	  }
	break;
      case SLANG_LE:
	for (n = 0; n < n_max; n++)
	  {
	     if (-1 == (*cmp) (a_type, (VOID_STAR)a, (VOID_STAR)b, &result))
	       return -1;
	     c[n] = (result <= 0);
	     a += da; b += db;
	  }
	break;
     }
   return 1;
}