Node:Dia Primitives, Next:, Previous:Dia Smobs, Up:Extending Dia



17.1.4 Writing Guile Primitives for Dia

Once the details of object representation are decided, writing the primitive function code that you need is usually straightforward.

A primitive is simply a C function whose arguments and return value are all of type SCM, and whose body does whatever you want it to do. As an example, here is a possible implementation of the square? primitive:

#define FUNC_NAME "square?"
static SCM square_p (SCM shape)
{
  struct dia_guile_shape * guile_shape;

  /* Check that arg is really a shape SMOB. */
  SCM_VALIDATE_SHAPE (SCM_ARG1, shape);

  /* Access Scheme-specific shape structure. */
  guile_shape = SCM_SMOB_DATA (shape);

  /* Find out if underlying shape exists and is a
     square; return answer as a Scheme boolean. */
  return SCM_BOOL (guile_shape->c_shape &&
                   (guile_shape->c_shape->type == DIA_SQUARE));
}
#undef FUNC_NAME

Notice how easy it is to chain through from the SCM shape parameter that square_p receives -- which is a SMOB -- to the Scheme-specific structure inside the SMOB, and thence to the underlying C structure for the shape.

In this code, SCM_SMOB_DATA and SCM_BOOL are macros from the standard Guile API. SCM_VALIDATE_SHAPE is a macro that you should define as part of your SMOB definition: it checks that the passed parameter is of the expected type. This is needed to guard against Scheme code using the square? procedure incorrectly, as in (square? "hello"); Scheme's latent typing means that usage errors like this must be caught at run time.

Having written the C code for your primitives, you need to make them available as Scheme procedures by calling the scm_c_define_gsubr function. scm_c_define_gsubr (REFFIXME) takes arguments that specify the Scheme-level name for the primitive and how many required, optional and rest arguments it can accept. The square? primitive always requires exactly one argument, so the call to make it available in Scheme reads like this:

scm_c_define_gsubr ("square?", 1, 0, 0, square_p);

For where to put this call, see the subsection after next on the structure of Guile-enabled code (see Dia Structure).