import zap prog(val rep (integer or float)) export zap prog(val rep (integer or float))Note the use of the keyword rep to indicate the use of the representative. To encode the value prior to calling the function zap(), the programmer would execute one of the following, depending on the type of the parameter for the call:
long rep_ptr; /* to hold the represented value */ float float_value; /* to be placed in representative */ ... /* first allocate a representative */ get_rep(&rep_ptr); /* then get enough memory to hold the data */ user_rep_new(rep_ptr, UTS_FLOAT_SIZE + UTS_TAG_SIZE); /* then put the data in the representative */ uts_encode_float(rep_ptr, float_value); zap(rep_ptr);to encode an integer:
long rep_ptr; /* to hold the represented value */ long int_value; /* to be placed in representative */ ... /* first allocate a representative */ get_rep(&rep_ptr); /* then get enough memory to hold the data */ user_rep_new(rep_ptr, UTS_INT_SIZE + UTS_TAG_SIZE); /* then put the data in the representative */ uts_encode_int(rep_ptr, int_value); zap(rep_ptr);To decode the value, the type must first be determined, then the value itself can be extracted and placed in a variable of the appropriate type:
zap(rep_ptr); long rep_ptr; /* the representative is allocated by the stub */ { float float_value; long int_value; /* attempt to extract one of the types */ if (uts_decode_float(rep_ptr, &float_value) == 1) ... processing for float ... /* if that fails, attempt to extract the other choice */ else (uts_decode_int(rep_ptr, &int_value) == 1) ... processing for integer ... /* if neither desired type is present, an error results */ else ... error handling here ... /* free memory that was allocated for representative */ dispose_rep(&rep_ptr); ... continue with zap() ...Consider the problem of passing command-line arguments to a user-supplied main function. In Schooner, such a function is named user_main() and the runtime will pass user-supplied command line arguments to it. The export specification for this case would be:
export user_main prog(val rep array [-] of string[-])The code needed to extract the arguments must first extract the size of the array (argc), then each string in the array can be decoded.
user_main(rep_ptr) long rep_ptr; /* the representative is allocated by the stub */ { int i; long argc, num_dims = 1, str_rep; char **argv; int str_len; /* extract the size of the argv[] array */ uts_dims(rep_ptr, &argc, &num_dims); if (argc != 0) { argv = (char **) malloc((argc + 1) * sizeof (char *)); for (i = 0; i < argc; i++++) { /* extract one string from the representative * note it is returned as a representative itself */ str_rep = uts_index(rep_ptr, i); str_len = uts_length(str_rep); if (str_len == -1) { ... error handling/reporting, bad string size ... return; /* so schx will shutdown components */ } str_len++++; /* leave room for terminating null */ argv[i] = (char *)malloc(str_len); /* now get the string from its representative */ if (uts_decode_string(str_rep, argv[i], str_len) == -1) { ... error handling/reporting, bad string size ... return; /* so schx will shutdown components */ } } argv[argc] = NULL; } else printf("user_main() received no command-line arguments\n"); dispose_rep(&rep_ptr); ... continue with user_main() ...Note:
uts_dims
returns the number of dimensions actually
found in the represented array.
In this example, this value is ignored since the
array is known to be one-dimensional. As a final example, consider the task of encoding and then decoding an array of floats where the array size is unknown at compile time. The UTS specification of such an array would be
var rep array[-] of floatThe user could then use the following two functions to handle the encoding and decoding of the values for this array:
# includeNote in the above example the use of the UTS tag and size information to ensure the data being decoded is of the correct type and size. The user is free to dispense with the error checking in cases where the information is known to be correct. These checks do, however, allow for handling varying types. Arrays of more than one dimension can also be handled. If some of the dimensions are fixed and others are varying, for example, the library routines can be used to make sure the fixed dimensions are correct before proceeding with the decoding of the values of the array. Similar techniques can be used in handling records containing unknown fields or holding fields of varying types.encode_array(size, rep_ptr, src) long size; long rep_ptr; float *src; { int i, j; /* allocate space for rep_ptr, including array header */ user_rep_new(rep_ptr, size * (UTS_FLOAT_SIZE + UTS_TAG_SIZE) + 50); uts_start_array(rep_ptr, 1, size); /* encode the actual array size */ /* encode each value */ for (i = 0; i < size; i++++) uts_encode_float(rep_ptr, *(src[i])); uts_end_array(rep_ptr); /* mark the end of the array */ rep_fixup(rep_ptr); /* let UTS get all the internal sizes correct */ } /* encode_array */ decode_array(size, rep_ptr, dest) int size; long rep_ptr; float *dest; { long index; /* index into represented array */ int dims, /* to hold size of array from representative */ num_dims; /* # of dimensions in represented array */ int i; num_dims = 1; if ( 1 != uts_dims(rep_ptr, &dims, &num_dims) ) { ... handle error ... } if (dims != size) { ... handle error ... } /* extract each value from the representative */ for (i = 0; i < size; i++++) { index = uts_index(rep_ptr, i); if ( 1 != uts_decode_float(index, &dest[i]) ) { ... handle error ... } } dispose_rep(&rep_ptr); /* free memory alloc'd for representative */ } /* decode_array */
void get_rep(Representative **) void dispose_rep(Representative **) void user_rep_new(Representative *, int) int uts_append_rep(Representative *dst, Representative *src) int rep_fixup(Representative *) used to get the lengths of arrays and records correctC routines for handling the UTS base types:
int uts_encode_float(Representative *, float) ERRCODE uts_decode_float(Representative *, float *) int uts_encode_double(Representative *, double) ERRCODE uts_decode_double(Representative *, double *) int uts_encode_int(Representative *, long) ERRCODE uts_decode_int(Representative *, long *) int uts_encode_bool(Representative *, int) ERRCODE uts_decode_bool(Representative *, int *) int uts_encode_string(Representative *, char *) int uts_decode_string(Representative *, char *dst, int size) returns -1 if string will not fit in dst (as determined by size), or there is not a string present; else, returns the actual string length int uts_encode_bytes(Representative *, char *, int size) int uts_decode_bytes(Representative *, char *, int size) int uts_length(Representative *) returns the length of a UTS_String or UTS_ByteC routines for handling UTS record types. Note the need to put in the start and end markers for the record, as well as the need to handle each individual field of the record. Since the length of a record is not generally known, the routine rep_fixup() can be used to get the lengths correct after all values have been placed in the representative.
int uts_start_record(Representative *) int uts_end_record(Representative *) ERRCODE uts_is_record(Representative *) int uts_rsize(Representative *) returns the number of fields in a UTS_record long uts_field(Representative *, int) selects the specified field from a UTS_Record, returns a Representative *; fields are numbered starting from zero.C routines for handling UTS array types. This first set of routines handles arrays with specific contents. They will correctly encode or decode the entire array, including needed headers and tags. In those routines where they occur,
num_dims
is the size of dim_array[ ]
, and dim_array
contains the size of each dimension of the array being encoded or
decoded.
int uts_encode_float_array(Representative *, float array[ ], int num_dims, int dim_array[ ]) int uts_encode_double_array(Representative *, double array[ ], int num_dims, int dim_array[ ]) int uts_encode_int_array(Representative *, int array[ ], int num_dims, int dim_array[ ]) ERRCODE uts_decode_float_array(Representative *, float array[ ], int num_dims, int dim_array[ ]) ERRCODE uts_decode_double_array(Representative *, double array[ ], int num_dims, int dim_array[ ]) ERRCODE uts_decode_int_array(Representative *, int array[ ], int num_dims, int dim_array[ ])These are general routines that can be used to encode and decode arrays containing any type of elements, including arrays that contain other arrays and/or records. Note the need to put in the start and end markers for the array, as well as the need to handle each individual element of the array. Since the length of an array is not always known, the routine rep_fixup() can be used to get the lengths correct after all values have been placed in the representative.
int uts_start_array(Representative *, int ndims, int dim1, [int dim2, ...]) int uts_end_array(Representative *) ERRCODE uts_is_array(Representative *) ERRCODE uts_dims(Representative *, int dim_array[], int *num_dims) dim_array[] contains the size of each dimension num_dims: in - size of dim_array[], out - number of dims int uts_asize(Representative *) returns the number of elements in a UTS_Array long uts_index(Representative *, int) selects a specified element from a UTS_Array, returns a Representative *These are provided mostly for use by the Schooner system code; however, they are also available to the C programmer.
int uts_encode_error(Representative *, long) ERRCODE uts_decode_error(Representative *, long *) int uts_encode_null(Representative *) ERRCODE uts_decode_null(Representative *) ERRCODE uts_is_null(Representative *) int uts_encode_sig(Representative *, Signature) ERRCODE uts_decode_sig(Representative *, Signature *) ERRCODE uts_is_sig(Representative *) int uts_encode_prog(Representative *, Prog *) ERRCODE uts_is_prog(Representative *)
subroutine getrep(int_var) subroutine disposerep(int_var) subroutine repnew(int_var, isize) integer function utsappendrep(src_int_var, dst_int_var) integer function repfix(int_var) used to get the lengths of arrays correctFortran routines for handling the UTS base types:
subroutine utsencodefloat(int_var, real_var) integer function utsdecodefloat(int_var, real_var) subroutine utsencodedouble(int_var, double_var) integer function utsdecodedouble(int_var, double_var) subroutine utsencodeint(int_var, int_var) integer function utsdecodeint(int_var, int_var) integer function utslen(int_var) returns the length of a UTS_String or UTS_ByteFortran routines for handling UTS record types. Note the need to put in the start and end markers for the record, as well as the need to handle each individual field of the record. Since the length of a record is not generally know, the routine repfix() can be used to get the lengths correct after all values have been placed in the representative.
integer function utsstartrecord(int_var) integer function utsendrecord(int_var) integer function utsisrecord(int_var) integer function utsrsize(int_var) returns the number of fields in a UTS_Record integer function utsfield(int_var, int) selects the specified field from a UTS_Record, returns a Representative *FORTRAN routines for handling UTS array types. The general routines are not complete; however, the routines for encoding and decoding various sized integer, float, and double arrays are. In those routines where they occur,
numdims
is the size of idim_array
, and idim_array
contains the size of each dimension of the array being encoded or decoded.
subroutine utsencodefloatarray(int_var, real_array, numdims, idim_array) integer function utsdecodefloatarray(int_var, real_array, numdims, idim_array) subroutine utscomputefloatarraysize(numdims, idim_array, length) length returns the number of bytes for the array subroutine utsencodearrayheader(int_var, numdims, idim_array, size) isize is the length returned by utscomputefloatarraysize integer function utsisarray(int_var) integer function utsdims(int_var, idim_array, num_dim) num_dims: in - size of dim_array, out - number of dims integer function utsasize(int_var) returns the number of elements in a UTS_Array integer function:utsindex(int_var, int) selects a specified element from a UTS_Array, returns a Representative *The following FORTRAN routines allow a part of a multi-dimensional array to be transmitted between FORTRAN components. They correctly handle the problem of an array of a declared size that is different from the array size that is passed to a subroutine or function. They have not been tested in passing these subset arrays to C; though, the behavior should be correct. In each routine, the
idecdims
array contains the declared
size of the original array, and iactualdims
contains the
actual dimensions of the subset of the array to be encoded.
isize
contains the length of the
subset of the array in bytes, as returned by
utscomputefloatarraysize
.
subroutine utsencode2dfloatarray(irepzap, realarray, iactualdims, idecdims, isize) subroutine utsencode3dfloatarray(irepzap, realarray, iactualdims, idecdims, isize) subroutine utsencode4dfloatarray(irepzap, realarray, iactualdims, idecdims, isize) subroutine utsencode5dfloatarray(irepzap, realarray, iactualdims, idecdims, isize) subroutine utsdecode2dfloatarray(irepzap, realarray, iactualdims, idecdims) subroutine utsdecode3dfloatarray(irepzap, realarray, iactualdims, idecdims) subroutine utsdecode4dfloatarray(irepzap, realarray, iactualdims, idecdims) subroutine utsdecode5dfloatarray(irepzap, realarray, iactualdims, idecdims)