next up previous contents index
Next: 16.3.2 Packing and Unpacking Up: 16.3 High-Level Primitives Previous: 16.3 High-Level Primitives

16.3.1 Invoices

The zip_new_invoice() call creates new invoices:

voidzip_new_invoice(Zip\_invoice const char *format, va_list ap)
The call zip_new_invoice() creates an invoice (**inv), while taking a variable number of arguments, starting with a format string (format) similar to the commonly used printf() strings. The format string contains one or more conversion specifications. A conversion specification is introduced by a percent sign (``%'') and is followed by:

For both the number of items to convert and stride, ``*'' or ``&'' can replace the hard-coded integer. If `*' is used, then the next argument in the argument list is used as an integer expression specifying the size of the conversion (or stride). Both the number of items to convert and the stride factor can be indirected by using ``&'' instead of an integer. The ``&'' indicates that a pointer to an integer should be stored, which will address the size of the invoice item (or stride) when it is packed. When ``&'' is used, the size is not evaluated immediately but is deferred until the actual packing of the data occurs. The ``&'' indirection consequently allows variable-size invoices to be constructed at runtime; we call this feature deferred sizing. The ``*'' allows the size of an invoice item (or stride) to be specified at run time.

One must be cautious of the scope of C variables when using ``&.'' For example, it is improper to create an invoice in a subroutine that has a local variable as a stride factor and then attempt to pass this invoice out and use it elsewhere, since the stride factor points at a variable that is no longer in scope. Unpredictable things will happen if this is attempted.

The single character types that are supported are as follows: ``c'' character,

``s'' short,

``i'' int,

``l'' long,

``f'' float, and

``d'' double. For each conversion specification, a pointer to an array of that type must be passed as an argument.

User-defined types may be added to the system to ease the packing of complicated data structures. An extra field (for passing whatever the user wants) may be passed to the conversion routines by adding ``(*)'' to the end of the user-type name. The ``-'' character can be used to skip space so that one can selectively push/pull things out of a letter. This allows for unpacking part of a letter and then unpacking the rest based on the part unpacked.

The following code would pack variable i followed by elements of the double_array.

    /* Example 1 */
    ZIP_MAILER *mlr;
    char *letter;
    ...

    Zip_Invoice*invoice;
    int i = 20; 
    double double_array[20];

    zip_new_invoice(``*invoice,%i%10.2d'', &i, double_array);
    ...

    /* use the invoice (see below) */
    letter = zip_malloc(mlr, zip_sizeof_invoice(mlr, invoice));
    length = zip_pack(mlr, invoice, ZIP_LETTER, 
                      &letter, ZIP_IGNORE);

    if(length == -1)      /* an error occurred */
       ...
The second example is a variant of the first. The first pack call is the same, while the second packs the first five elements of the double_array.

    /* Example 2 */
    int len = 10, stride = 2;
    zip_new_invoice(``*invoice,%i%&.&d'', &i, &len, &stride, 
                              double_array);

    /* use the invoice */
    letter = zip_malloc(mlr, zip_sizeof_invoice(mlr, invoice));
    length = zip_pack(mlr, invoice, ZIP_LETTER, &letter, 
                      ZIP_IGNORE);
    ...
    len = 5;  /* set the length and stride for this use 
                 of the invoice */
    stride = 1; 

    /* use the invoice */
    letter = zip_malloc(mlr, zip_sizeof_invoice(mlr, invoice));
    length = zip_pack(mlr, invoice, ZIP_LETTER, &letter, 
                      ZIP_IGNORE);
If a user-defined type matrix has been added to the system to pack matrix structures, then the following example shows how matrix-type data can be used in an invoice declaration. See also below on how to add a user-defined type.

    /* Example 3 */
    struct matrix M;   /* some user-defined type */
    int i;
    Extra extra; /* contains some special info on packing a  */ 
                 /* `matrix'; often this will not be needed, */
                 /* but this feature is provided for */ 
                 /* flexibility */

    zip_new_invoice(``*invoice,%i%matrix(*)%20d'', &i, &M, 
                              &extra, double_array);
At times it might be useful to know the size (in bytes) that is needed to hold the variables specified by an invoice. zip_sizeof_invoice returns the size (in bytes) that the invoice will occupy when packed. We have already used this in several examples above.

    int zip_sizeof_invoice(ZIP_MAILER *mailer, Zip_Invoice *inv)
To delete an existing invoice when there is no more need for it use zip_free_invoice():
    void zip_free_invoice(Zip_Invoice **inv)
This will free up the specified invoice and set *inv = NULL to help flag accidental access.

User-defined types for pack and unpack routines are defined using a registry mechanism provided by Zipcode.

int zip_register_invoice_type(char *name, Method *in, Method
                              *out, Method *len, Method *align)
The structure Method is a composite of a pointer-to-function, and additional state information for a function call. The details of Method declarations are beyond the scope of this presentation.

In the above, name is the user-defined name for the auxiliary type. User-defined names follow the ANSI standard for C identifiers. They begin with a nondigit (characters ``A'' through ``Z,'' ``a'' through ``z,'' and the underscore ``_''), followed by one or more nondigits or digits. User-defined type names currently have global scope so beware of name conflicts. User-defined types cannot be the same as one of the built-in types specified above. The in, out, len, and align are the Methods used to pack/unpack the user-defined type. They must have the following parameter lists

    int in(ZIP_MAILER *mailer, void *src, void *dest, 
                           int num_items, int stride, 
                           Extra *extra)

    int out(ZIP_MAILER *mailer, void *src, void *dest, 
            int num_items, int stride, Extra *extra)
        
    int align(ZIP_MAILER *mailer, void *dest, Extra *extra)

    int len(ZIP_MAILER *mailer, int num_items, int stride, 
            Extra *extra)
Here, src is a pointer to the items to be converted and the dest parameter is a pointer to the space where converted items are stored. In addition, num_items is the number of items to be converted, stride is a stride factor for striding through arrays, and extra is used to pass any miscellaneous information that is needed by the conversion. The user can pass an extra using the `%user-type(*)' notation discussed in zip_new_invoice.

The align variable returns the number of bytes to be added to dest to align the value properly. The purpose of len is to return the total size of num_items, in bytes; the in() and out() functions perform the conversion.

Finally, to remove a user-defined type from the system use the

    
int zip_unregister_invoice_type(char *name)
call. Invoking zip_unregister_invoice_type deletes the entry for the named type, which cannot be used after this call has been made.



next up previous contents index
Next: 16.3.2 Packing and Unpacking Up: 16.3 High-Level Primitives Previous: 16.3 High-Level Primitives



Guy Robinson
Wed Mar 1 10:19:35 EST 1995