/* Array manipulation routines for S-Lang */ /* * Copyright (c) 1992, 1994 John E. Davis * All rights reserved. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. Permission is not granted to modify this * software for any purpose without written agreement from John E. Davis. * * IN NO EVENT SHALL JOHN E. DAVIS BE LIABLE TO ANY PARTY FOR DIRECT, * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOHN E. DAVIS * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * JOHN E. DAVIS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" * BASIS, AND JOHN E. DAVIS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include #include #include "slang.h" #include "_slang.h" #include "slarray.h" /* Array Stuff */ #define MAX_ARRAYS 256 static SLArray_Type *Array_Table[MAX_ARRAYS]; static void free_array_handle (int hand) { SLArray_Type *a = Array_Table[hand]; if (a == NULL) { SLang_doerror ("Array is not allocated."); return; } if (a->flags) { SLang_doerror ("Freeing an intrinsic array is illegal."); return; } Array_Table[hand] = NULL; FREE( a->ptr ); FREE(a); } /* This routine may be called by application to free array handle created by * the application. Returns 0 upon success, -1 if the handle is invalid and * -2 if the handle is not associated with a C array. */ int SLang_free_array_handle (int hand) { SLArray_Type *a = Array_Table[hand]; if (a == NULL) return -1; if (a->flags == 0) return -2; Array_Table[hand] = NULL; FREE(a); return 0; } static int alloc_array_handle (void) { SLArray_Type **a, **amax; a = Array_Table; amax = a + MAX_ARRAYS; while (a < amax) { if (*a == NULL) return ((int) (a - Array_Table)); a++; } SLang_doerror ("Array limit exceeded."); return -1; } /* if ptr == NULL then malloc space. Otherwise assume space is at ptr */ int SLcreate_array(long *ptr, int dim, int d0, int d1, int d2, unsigned char t, unsigned char flags) { unsigned long n, size; unsigned char type; SLArray_Type *at; int hand; switch (t) { case 'i': type = INT_TYPE; size = sizeof(int); break; case 's': type = STRING_TYPE; size = sizeof(char *); break; case 'c': type = CHAR_TYPE; size = sizeof(char); break; #ifdef FLOAT_TYPE case 'f': type = FLOAT_TYPE; size = sizeof(FLOAT); break; #endif default: return (-1); } /* This must be since indices go from 0 to d - 1 */ if (d1 < 1) d1 = 1; if (d2 < 1) d2 = 1; n = d0; n = n * d1; n = n * d2; if (-1 == (hand = alloc_array_handle ())) return hand; if (NULL == (at = (SLArray_Type *) MALLOC(sizeof(SLArray_Type)))) { return -1; } if (ptr == NULL) { if (size == 1) ptr = (long *) MALLOC(n); else ptr = (long *) CALLOC(n, size); if (ptr == NULL) return (-1); } Array_Table [hand] = at; at->ptr = (long) ptr; at->dim = dim; at->x = d0; at->y = d1; at->z = d2; at->type = type; at->flags = flags; return(hand); } void SLpush_array (int at) { SLang_Object_Type obj; obj.type = LANG_DATA | (ARRAY_TYPE << 8); obj.v.i_val = at; SLang_push(&obj); } void SLang_create_array(void) { int dim, d0, d1, d2, t; int at; if (SLang_pop_integer(&dim)) return; if (dim > 3) { SLang_doerror("Array size not supported."); return; } d1 = d0 = d2 = 1; switch(dim) { case 3: SLang_pop_integer(&d2); case 2: SLang_pop_integer(&d1); case 1: SLang_pop_integer(&d0); } if (SLang_pop_integer(&t)) return; at = SLcreate_array(NULL, dim, d0, d1, d2, t, 0); if (at == -1) { SLang_doerror("Unable to create array."); return; } SLpush_array (at); } void SLfree_array(void) { SLang_Object_Type obj; if (SLang_pop(&obj)) return; if ((obj.type >> 8) != ARRAY_TYPE) { SLang_Error = TYPE_MISMATCH; return; } free_array_handle (obj.v.i_val); } /* returns the array referenced by handle h */ SLArray_Type *SLarray_from_handle (int h) { return Array_Table[h]; } /* returns array. If *stype is non-zero, a string is accepted as an array. If an actual array is popped, *stype will be zero upon return. However, if *stype is such that a string is permitted, *stype will be 1 if the string that is returned (through the cast) should be freed. */ SLArray_Type *SLang_pop_array(int *sflag) { SLang_Object_Type obj; unsigned short t; if (SLang_pop(&obj)) return(NULL); t = obj.type; if ((t >> 8) != ARRAY_TYPE) { if ((*sflag == 0) || ((t >> 8) != STRING_TYPE)) { SLang_Error = TYPE_MISMATCH; return(NULL); } if ((t & 0xFF) == LANG_DATA) *sflag = 1; else *sflag = -1; return (SLArray_Type *) obj.v.s_val; } *sflag = 0; return SLarray_from_handle (obj.v.i_val); } static char *Bound_err = "Array dims out of bounds"; static unsigned int compute_array_offset(SLArray_Type *at) { int elem[3], el, x[3], d, dim; unsigned int off; if (SLang_Error) return(0); dim = at->dim; x[0] = at->x; x[1] = at->y; x[2] = at->z; elem[0] = elem[1] = elem[2] = 0; d = dim; while (d--) { if (SLang_pop_integer(&el)) return(0); if ((el >= x[d]) || (el < 0)) { SLang_doerror(Bound_err); return(0); } elem[d] = el; } off = 0; d = 0; off = (elem[0] * x[1] + elem[1]) * x[2] + elem[2]; return(off); } static void str_get_elem(unsigned char *s, int dat) { int n, nmax, ch; if (SLang_pop_integer(&n)) goto done; nmax = strlen((char *) s); if (nmax < n) { SLang_doerror(Bound_err); goto done; } ch = s[n]; SLang_push_integer(ch); done: if (dat == 1) FREE(s); } void SLarray_putelem() { SLArray_Type *at; unsigned int off; int sdat, i, *ip; char *str, *newstr, **sp; unsigned char *p, *ic; #ifdef FLOAT_TYPE FLOAT f, *fp; int ix; int convert; #endif sdat = 0; if (NULL == (at = SLang_pop_array(&sdat))) return; if (at->flags == LANG_RVARIABLE) { SLang_Error = READONLY_ERROR; return; } off = compute_array_offset(at); if (SLang_Error) return; p = (unsigned char *) at->ptr; switch(at->type) { case INT_TYPE: if (SLang_pop_integer(&i)) return; ip = (int *) (off + (int *) p); *ip = i; break; case STRING_TYPE: if (SLang_pop_string(&str, &sdat)) return; newstr = (char *) SLmake_string(str); if (sdat == 1) FREE(str); sp = (char **)(off + (char **) p); if (NULL != *sp) FREE(*sp); *sp = newstr; break; case CHAR_TYPE: if (SLang_pop_integer(&i)) return; ic = (unsigned char *)(off + (unsigned char *) p); *ic = (unsigned char) i; break; #ifdef FLOAT_TYPE case FLOAT_TYPE: if (SLang_pop_float(&f, &convert, &ix)) return; (void) convert; (void) ix; fp = off + (FLOAT *) p; *fp = f; break; #endif default: SLang_doerror("Corrupted Array."); } return; } static void array_push_element(SLArray_Type *at, int off) { unsigned char *p; p = (unsigned char *) at->ptr; switch(at->type) { case INT_TYPE: SLang_push_integer((int) *(((int *) p) + off)); break; case CHAR_TYPE: SLang_push_integer((int) *(((unsigned char *) p) + off)); break; case STRING_TYPE: if (NULL == (p = (unsigned char *) *(((char **) p) + off))) { SLang_doerror("Array Element uninitialized."); } else SLang_push_string((char *) p); break; #ifdef FLOAT_TYPE case FLOAT_TYPE: SLang_push_float((FLOAT) *(((FLOAT *)p) + off)); break; #endif default: SLang_doerror("Internal Error in array element."); } } void SLarray_getelem() { SLArray_Type *at; unsigned int off; int sdat = 1; if (NULL == (at = SLang_pop_array(&sdat))) return; if (sdat) { str_get_elem((unsigned char *) (long) at, sdat); return; } off = compute_array_offset(at); if (SLang_Error) return; array_push_element(at, off); } void SLcopy_array (void) { SLArray_Type *a, *b; int sa = 0, sb = 0; unsigned int size; if ((NULL == (b = SLang_pop_array (&sb))) || (NULL == (a = SLang_pop_array (&sa)))) { return; } /* array a must be writable and a and b must be identical */ if (a->flags == LANG_RVARIABLE) { SLang_Error = READONLY_ERROR; return; } if ((a->dim != b->dim) || (a->x != b->x) || (a->y != b->y) || (a->z != b->z) || (a->type != b->type)) { SLang_Error = TYPE_MISMATCH; return; } switch (a->type) { case INT_TYPE: size = sizeof(int); break; case STRING_TYPE: size = sizeof(char *); break; case CHAR_TYPE: size = sizeof(char); break; #ifdef FLOAT_TYPE case FLOAT_TYPE: size = sizeof(FLOAT); break; #endif default: return; } /* I might want to loosen the restriction about the actual dimensions and * simply demand that the size be the same */ size = size * a->x * a->y * a->z; MEMCPY ((char *)a->ptr, (char *)b->ptr, size); } int SLang_add_array(char *name, long* addr, int dim, int d0, int d1, int d2, unsigned char t, unsigned char flags) { unsigned short type; int hand; if (-1 != (hand = SLcreate_array(addr, dim, d0, d1, d2, t, flags))) { type = LANG_IVARIABLE | (ARRAY_TYPE << 8); SLadd_name(name, (long) hand, type); } return hand; } void SLarray_sort(char *f) { SLArray_Type *at_str, *at_int; unsigned char type; SLang_Name_Type *entry; SLang_Object_Type obj; int sdat; int l, j, ir, i, rra, n, cmp; int *ra; int hand; if ((NULL == (entry = SLang_locate_name(f))) || (*entry->name == 0)) { SLang_doerror("Sort function undefined."); return; } type = entry->type & 0xFF; if (type != LANG_FUNCTION) { SLang_doerror("Invalid sort function."); return; } sdat = 0; if (NULL == (at_str = SLang_pop_array(&sdat))) return; if (at_str->flags == LANG_RVARIABLE) { SLang_Error = READONLY_ERROR; return; } n = at_str->x; if (at_str->dim != 1) { SLang_doerror("Sort requires 1 dim arrays."); return; } if (-1 == (hand = SLcreate_array(NULL, 1, n, 1, 1, 'i', 0))) { SLang_doerror("Error Creating index array."); return; } at_int = Array_Table[hand]; ra = (int *) at_int->ptr; ra--; for (i = 1; i <= n; i++) ra[i] = i; /* heap sort from adapted from numerical recipes */ l = 1 + n / 2; ir = n; while(1) { if (l > 1) rra = ra[--l]; else { rra = ra[ir]; ra[ir] = ra[1]; if (--ir <= 1) { ra[1] = rra; for (i = 1; i <= n; i++) ra[i] -= 1; obj.type = LANG_DATA | (ARRAY_TYPE << 8); obj.v.i_val= hand; SLang_push(&obj); return; } } i = l; j = 2 * l; while(j <= ir) { if (j < ir) { array_push_element(at_str, ra[j] - 1); array_push_element(at_str, ra[j + 1] - 1); SLexecute_function(entry); if (SLang_pop_integer(&cmp)) goto return_err; if (cmp) j++; } array_push_element(at_str, rra - 1); array_push_element(at_str, ra[j] - 1); SLexecute_function(entry); if (SLang_pop_integer(&cmp)) goto return_err; if (cmp) { ra[i] = ra[j]; i = j; j += j; } else j = ir + 1; } ra[i] = rra; } return_err: free_array_handle (hand); } void SLinit_char_array() { int dat, sdat; SLArray_Type *at; unsigned char *s; unsigned int n, ndim; if (SLang_pop_string((char **) &s, &dat)) return; sdat = 0; if (NULL == (at = SLang_pop_array(&sdat))) goto free_and_return; if (at->type != CHAR_TYPE) { SLang_doerror("Operation requires character array."); goto free_and_return; } n = (unsigned int) strlen((char *)s); ndim = at->x * at->y * at->z; if (n > ndim) { SLang_doerror("String too big to init Array."); goto free_and_return; } strncpy((char *) at->ptr, (char *) s, (int) ndim); free_and_return: if (dat == 1) FREE(s); }