Yazoo runs embedded C or C++ functions via its a built-in call() routine. Those embedded functions must be of the following form (compare with C's int main()):
int MyFunction(int argc, char **argv)
{
...
}
Of course the names of the variables MyFunction, argc and argv are arbitrary. As in a main() function, when the function is executed argc stores the number of arguments to the function, and argv points to an array of pointers to the arguments. Thus *argv is the pointer to the first argument, *(argv+1) is the pointer to the second argument, and *(argv+argc-1) points to the last argument. Any given argument will contain either numbers (integers or floats), blocks of non-numeric byte data, or strings contained in linked lists.
Consider the following call from a Yazoo script:
names[2][5] :: double
...
call("MyFunction", 1, counter, names[*][*], 14)
This passes three variables and one array to a C function. It was a two-dimensional array, but all arrays get unravelled into one-dimensional lists before being handed off to C routines. The order of elements in the list is 1-1, 1-2, ..., 1-5, 2-1, ..., 2-5. Since the third argv argument is pointed at by *(argv+2), the array element names[2][3] -- eighth in the list -- would be accessed in the C function by writing
double names_2_3;
double *names_array = (double *) *(argv+2);
names_2_3 = *(names_array+7);
In a sense each argument to a C function is treated as an array; simple variables are just arrays of size one. So the C code would pick up its first argument by writing *(signed long *) *argv (as slong is the default type for integers).
Strings are a bit more complicated. Internally, they are stored in linked lists that can change their sizes to accommodate strings of different lengths. In principle a string could be passed to C code as a byte array. That approach wasn't taken because it wouldn't allow the C routine to change the size of the string. So instead, call() passes a pointer to Yazoo's own personal linked list that holds the string. This is quite risky on Yazoo's part, since it will suffer speedy or slow death if the user mismanages the linked list. The user is therefore encouraged to make use of Yazoo's tried and tested linked-list routines when dealing with string arguments; those routines are encoded in lnklst.c and described later in this document.
All numeric arguments are arrays (often of size 1), and all strings are linked lists. Putting two and two together, we can guess, correctly, that an argument that is a single string is an array, containing one element, of type linkedlist (defined in lnklst.h). Given the following Yazoo call
last_names[10] :: first_name :: string
...
call("Lookup", last_names, first_name)
an appropriate C interface might begin
#include "lnklst.h"
int Lookup(int argc, char **argv)
{
linkedlist *last = (linkedlist *) *argv; // must be a _pointer_
linkedlist *first = (linkedlist *) *(argv+1); // to the linked list
linkedlist *first_last_name, *last_last_name;
first_last_name = last+0;
last_last_name = last+9;
...
}
(Note that we must include the linked list header file.) An inappropriate way of handling the linked lists would be to work with copies of the linked list rather than the pointers to the originals.
linkedlist first_last_name, last_last_name;
...
last_last_name = *(last+9); // asking for trouble
The linkedlist variable itself stores important information that needs to be up-to-date; if the C routine were to resize the string, Yazoo would never know about it and would probably crash somewhere down the line.
One final service that call() provides is to furnish the argv list with an info table on the sizes and types of its arguments. This is useful for type-checking -- since the user's C routine would probably crash if given parameters of the wrong size -- and it also allows one to write C functions that accept variables and arrays whose types and dimensions cannot be known beforehand.
The info list is found after all the other arguments, at *(argv+argc). It has one entry of type arg_info for each of the argc arguments that was passed. The arg_info type is defined in userfn.h: it contains the three unsigned longs arg_type, arg_size, and arg_indices. arg_type is the numeric type designation from Table 1. Composite types are listed in the table; however, the user will never see one passed to a function, since their primitive constituents are passed as separate argv entries. arg_indices is the number of array elements (remember, each argument is an array), which for multi-dimensional arrays is the product of ranges of each dimension. The arg_size field denotes the size, in bytes, of each element (not of the whole array), and is useful for block types which may be sized arbitrarily. Note that many of these quantities are machine-dependent, and that Yazoo rolls with the local C conventions on each computer. For example, machines with 32-bit addressing will have 4-byte long words, but 64-bit machines have 8-byte long words.
type ID | type name | Yazoo name | C def name | byte size* | min value* | max value* |
0 | unsigned byte | ubyte | Ubyte_type | 1 | 0 | 255 |
1 | signed byte | sbyte | Sbyte_type | 1 | -128 | 127 |
2 | unsigned short | ushort | Ushort_type | 2 | 0 | 216-1 |
3 | signed short | sshort | Sshort_type | 2 | -215 | 215-1 |
4 | unsigned long | ulong | Ulong_type | 4 | 0 | 232-1 |
5 | signed long | slong | Slong_type | 4 | -231 | 231-1 |
6 | single-precision float | single | single_type | 2 | -1038 | 1038 |
7 | double-precision float | double | double_type | 8 | -1038 | 1038 |
8 | block type | block N | block_type | N | N/A | N/A |
9 | string type | string | string_type | any | N/A | N/A |
10 | composite type | {...} | composite_type | any | N/A | N/A |
The info list is accessed in the same way as any of the other arguments.
#include "lnklst.h"
int MyFunction(int argc, char **argv)
{
arg_info ArgsList;
long counter;
const char ExpectedTypes = { 0, 5, 7, 7 };
...
if (argc != 4) return 1;
ArgsList = *(arg_info *) *(argv + argc);
for (counter = 1; counter <= 4; counter++)
{
if ((ArgsList + counter - 1)->arg_type != *(ExpectedTypes + counter)) return 2;
if ((ArgsList + counter - 1)->arg_indices != 1) return 3;
}
...
}
For readability, each Yazoo type has an associated name (e.g. double_type) which can be used in place of its number. This name appears in the third column of Table 1. The names themselves are defined in yazooh.h, so the user needs to include this header file in any source file that uses them.
Last update: July 28, 2013