DATASERV (kapputils) functions


LIBRARY ROUTINE

KCALL - wrapper to simplify the use of dataservices and other common calls in a kroutine library routine

LIBRARY CALL

void KCALL( func )

INPUT

OUTPUT

none

RETURN VALUE

none

DESCRIPTION

KCALL is a macro that can be used to greatly simplify the use of dataservices calls in a kroutine library routine. When set up properly with the required auxillary variables, KCALL will call the desired function and automatically check the return values for an error condition. If an error occurs, KCALL will examine the function that was called and automatically print out an appropriate error message before returning from the code containing the KCALL macro with a return value of zero (appropriate for lkroutines). If the environment variable KHOROS_NOTIFY is set to "verbose", then the actual text of the function that returned the error condition will be printed too, simplifying debugging.

In addition to checking for errors and printing error messages, KCALL will automatically use klist_free() with the lkcall_free() support routine to automatically return any resources in a klist called objlist to the system if an error is detected. This mechanism allows the programmer to simply place dynamically allocated resources on the objlist as they are needed, and forget about having to explicitly free them under fault conditions.

Consistent use of KCALL can make your code much more rubust to subtle failures (such as forgetting to check the return status of each dataservices call) as well as make it much shorter and more readable.

KCALL requires that the following auxillary variables be available in the program unit where KCALL will be used:

Variable Use -------- --- char *lib Name of library to put in error message char *rtn Name of lkroutine to put in error message klist *objlist klist of objects to be automatically kfree_and_NULL()'d if an error is detected

A typical initialization of these variables might be as follows (this example stolen from the lkfft.c routine):

char *lib = "kdatamanip", *rtn = "lkfft"; klist *objlist=NULL;

Following are some examples of how KCALL might be used to accomplish various tasks:

Referencing an object KCALL((in_obj = kpds_reference_object(in_obj)) != KOBJECT_INVALID); objlist = klist_add(objlist,in_obj,"KOBJECT");

Getting an attribute KCALL(kpds_get_attribute(in_obj, KPDS_LOCATION_GRID, &grid));

Setting an attribute KCALL(kpds_set_attribute(in_obj,KPDS_VALUE_DATA_TYPE, KDCOMPLEX));

Creating a segment KCALL(kpds_create_value(cmplx_out));

Copying object attributes KCALL(kpds_copy_object_attr(cmplx_out,cmplx_ref));

Allocating some dynamic memory with kmalloc() KCALL(!((cmplx_data = (kdcomplex *) kmalloc(numo*ksizeof(kdcomplex))) == NULL)); objlist = klist_add(objlist,cmplx_data,"KMALLOC"); This one is a bit strange; note that the KCALL macro only checks to see that it got a non-zero value back from the function or expression that it is called with; the multiple levels of parenthesis and the ! operator arrange for this behavior to be seen by KCALL.

Getting data KCALL(!((cmplx_data = (kdcomplex *) kpds_get_data(in_obj,KPDS_VALUE_REGION, (kaddr)cmplx_data)) == NULL)); or KCALL(kpds_get_data(in_obj,KPDS_VALUE_REGION, (kaddr)cmplx_data));

Putting data KCALL(kpds_put_data(cmplx_out,KPDS_VALUE_REGION, (kaddr)cmplx_data));

Adding something to the objlist objlist = klist_add(objlist,in_obj,"KOBJECT"); Note here that the string "KOBJECT" eventually tells the code that frees things on the klist that this is a kobject and should be freed with kpds_close_object(). If the object being added was obtained using kmalloc() (or should simply be freed using a call to kfree_and_NULL(), then use the string "KMALLOC" instead of "KOBJECT".

Removing something from the objlist objlist = klist_delete(objlist,in_obj);

Causing everything on the objlist to be released back to the system (kfree_and_NULL'd) (void)klist_free(objlist,(kfunc_void)lkcall_free);

Remember that KCALL is expanded as a MACRO; the code that KCALL expands into is called as if it had been in place in your code, right where the KCALL macro is placed. So, KCALL has access to those variables scoped at that the program unit containing the KCALL macro, and anything KCALL does behaves as code executed in that program unit would behave. For example, if KCALL detects an error and executes it's return(0) statement, then the effect is the same as if a return statement had been placed in your code right were the KCALL macro was placed, namely you get a return(0) from the enclosing subroutine. KCALL is not a function or subroutine!

ADDITIONAL INFORMATION

none

EXAMPLES

Check out one of the lkroutines in the $DATAMANIP library,
such as lkhisto.c to see real-life use of KCALL.

Also see the man page for lkcall_free(), which has a simplified example of using KCALL and lkcall_free().

SIDE EFFECTS

none

RESTRICTIONS

The follwing auxillary variables are referenced by the KCALL macro and must be present in the program unit where KCALLs are used:

Variable Use -------- --- char *lib Name of library to put in error message char *rtn Name of lkroutine to put in error message klist *objlist klist of objects to be automatically kfree_and_NULL()'d if an error is detected

MODIFICATION

none

FILES

$DATASERV/include/kapputils/kapputils.h

SEE ALSO

kapputils(3)

COPYRIGHT

Copyright (C) 1993 - 1997, Khoral Research, Inc. ("KRI") All rights reserved.