Next: callback_fun Up: User Function Help File Previous: arginfo_fun   Contents

c_macros

Usage:
type userfunhelp(c_macros) for information on available C_macros for compiling
  user functions that may be compiled for more than one type of computer.



Keywords: user functions, coding, sample source
This topic presumes familiarity with topics User(), user_fun,
arginfo_fun and callback_fun.  It describes the use of the C macros in
header file Userfun.h in writing user functions in such a way that their
code may be compiled on a variety of computers with little or no change.
Some of the macros in Userfun.h are helpful even when writing a user
function to run on a single type of computer.  Among other things, use
of these macros ensures that all non-symbol arguments end up as pointers
and symbol arguments end up as handles.  They can also make it easier to
call back to MacAnova.  See callback_fun.

To make these macros available, the following should appear in your
source file
  #include "Userfun.h"
and both files Userfun.h and dynload.h (included by Userfun.h) should be
in the same directory as the file being compiled.

Userfun.h also includes macros for working directly with Macanova
symbols.  These are not discussed here.  However, example source
fooeval.c includes some example of their use.  See Userfun.h for more
information.

Userfun.h also defines constants for describing the type and shape of
user function arguments.  See topic type_codes for a complete list.

Here is a brief summary of the most important macros in Userfun.h.

Prefix each user and arginfo function name with EXPORTED:
  void EXPORTED foo(...)
or
  long * EXPORTED arginfo_fooeval(void)

If MACINTOSH is defined, the macros referencing arguments (THEARG,
THECOMMAND, THESYMBOL, CALLBACKFUN) normally assume the arguments are
handles; if MACINTOSH is not defined, they normally assume arguments are
pointers.

If, for some reason, you want to deviate from this convention, you can
override it by using one of the following
  #define POINTERARGS 1  /*arguments assumed to be pointers*/
or
  #define POINTERARGS 0  /*arguments assumed to be handles*/

If POINTERARGS is not defined, Userfun.h defines it to be 0 on a
Macintosh or 1 otherwise.

Use DOUBLEARG(argx), CHARARG(argx), LONGARG(argx) and SYMBOLARG(argx) to
declare arguments other than a list of call back functions.  They expand
to handles (double ** argx, char ** argx, long ** argx, Symbol ** argx)
when POINTERARGS is 0 (Macintosh) and to pointers (double * argx, char *
argx, long * argx, Symbol * argx) when POINTERARGS is 1 (everywhere
else).  If you do deviate and do not provide an arginfo function (see
arginfo_fun), you will have to include either pointers:T (Macintosh) or
pointers:F (otherwise) as an argument to User().

Use CALLBACKLIST(funlist) to declare the call back function list
structure.  It expands to MacAnovaCBSH funlist (a handle) when
POINTERARGS is 0 and to MacAnovaCBSPtr funlist (a pointer) otherwise.

Use arg = THEARG(argx) to obtain a pointer to non-symbol argument.  This
expands to arg = *argx (dereferencing a handle) when POINTERARGS is 0
and to arg = argx otherwise.  On a Macintosh, you should dereference any
handle argument again after calling back to a function internal to
MacAnova.

Use commandH = THECOMMAND(argx) to obtain a handle (char **) to a
CHARACTER argument that is to be an argument to the mvEval() call back
function.

Use symhArg = THESYMBOL(argx) to obtain a Symbolhandle (Symbol **) for a
symbol type argument.

Use CALLBACKFUN(funlist, funName) to obtain a pointer to function
funName in the list of call back functions.

In any user function making callbacks define C macro MVCALLBACKS before
include Userfun.h.  This results in the declaration of MvCallbackFuns, a
global handle or pointer (depending on the value of POINTERARGS) to a
call back function list.  It this case, one of the first executable
lines in the user function should be setMvFuns(funlist) to initialize
MvCallbackFuns.  Subsequently you can call the standard call back
functions by mvPrint(msg), mvAlert(msg), mvEval(cmd), mvIsmissing(&x),
mvSeterror(errorNumber), and mvFindfun(funName), where msg, cmd and
funName have type char *, x has type double and errorNumber has type
long.  For example, mvPrint("Hello!") expands to
CALLBACKFUN(MvCallbackFuns, print)("Hello").

When compiling for a 68K Macintosh, Userfun.h defines PRAGMAMPWC.  This
is to be used as follows:

  #ifdef PRAGMAMPWC
  #pragma mpwc on
  #endif

  Declaration of arginfo or call back function(s)

  #ifdef PRAGMAMPWC
  #pragma mpwc off
  #endif

This ensures the use of function calling conventions that are compatible
with the 68K version of MacAnova which is compiled using MPW C.  See the
sample files goo.c and fooeval.c below for examples of the use of
PRAGMAMPWC.

If the user function makes call backs and has more than one source file,
define USERSUBFUNCTION in all but one source file.  This assures that
MvCallbackFuns will not be multiply defined.

In topic user_fun is C code not using these macros for user function goo
and its arginfo function arginfo_goo.  Separate versions are given there
for Macintosh and non-Macintosh use.  Here is C code for these functions
that uses the macros.  It should compile correctly on all platforms.
When compiled for a 68K Macintosh, two compilation runs will be
required, changing the value of WHICHFUN (1 for goo, 2 for arginfo_goo).

Use of these macros requires that MACINTOSH be defined when compiling
for a Macintosh (with powerc also defined for PPC and MW_CW defined if
using Metrowerks CodeWarrior compiler), DJGPP is defined when compiling
for use with the protected mode DOS version, and WIN32 is defined when
compiling for use with the Windows version.

The use of macros such as USERFUN and ARGINFO to define function names
is needed to meet the requirements for Macintosh compilation for which
an entry point must be named 'main'.  The conditional compilation of the
user function and arginfo function (depending on whether MAINFUN and/or
INFOFUN is defined) is in response to limitations on compilations for a
68K Macintosh for which there can be only one entry point per resource.

We suggest the examples below, source for which is distributed with
MacAnova) be used as templates, changing most of the executable code and
the augument lists to meet your particular needs.

File goo.c:
  #include "Userfun.h"

  #ifndef MACINTOSH
  #define MAINFUN    /*main entry will be compiled*/
  #ifndef DJGPP
  #define INFOFUN    /*arginfo entry will be compiled*/
  #endif /*DJGPP*/
  #define USERFUN goo
  #define ARGINFO arginfo_goo
  #else /*!MACINTOSH*/

  /*
      For PPC MAC, one function must be called main
      For 68K MAC, only one function is reachable per compilation
      project and it must be called main
  */
  #ifdef powerc
  #define MAINFUN    /*main entry will be compiled*/
  #define INFOFUN    /*arginfo entry will be compiled*/
  #define main_goo main
  #else /*powerc*/

  /* define which of the 2 functions will be compiled*/
  #define WHICHFUN 1  /*must be 1 or 2 */
  #if WHICHFUN == 1
  #define MAINFUN
  #else
  #define INFOFUN
  #endif

  #if defined(MAINFUN)
  #define main_goo    main
  #else
  #define info_goo    main
  #endif

  #endif /*powerc*/

  #define USERFUN      main_goo
  #define USERFUNENTRY goo
  #define ARGINFO      info_goo
  #define ARGINFOENTRY arginfo_goo

  #endif /*!MACINTOSH*/

  #ifdef MAINFUN
  /*
    EXPORTED is _export for Windows compiled by Borland C/C++ 4.5
    DOUBLEARG(argx) expands as double * argx or double ** argx, and
    similarly for LONGARG(argn)
  */
  void EXPORTED USERFUN(DOUBLEARG(argx), DOUBLEARG(argy), LONGARG(argn),
      DOUBLEARG(argresult))
  {
      /* THEARG(argx) expands as argx or *argx */
      double      *x = THEARG(argx);
      double      *y = THEARG(argy);
      long        *n = THEARG(argn);
      double      *result = THEARG(argresult);
      int          i;

      EnterCode();
      *result = 0.0;
      for (i = 0; i < *n; i++)
      {
          *result += x[i]*y[i];
      }
      ExitCode();
  }
  #endif /*MAINFUN*/

  #ifdef INFOFUN
  static long Gooarginfo[] =
  {
      4, NOCALLBACK | POINTERUSE | NOSYMBOLARGS,
      NONMISSINGREALVECTOR, NONMISSINGREALVECTOR, LONGSCALAR, REALSCALAR
  };

  #ifdef PRAGMAMPWC /*PRAGMAMPWC defined in Userfun.h only for 68K Mac*/
  #pragma mpwc on
  #endif /*PRAGMAMPWC*/
  long * EXPORTED ARGINFO(void)
  {
      long         *arginfo;

      EnterCode();

      arginfo = Gooarginfo;
      CHECK68881(arginfo);

      ExitCode();

      return(arginfo);
  }
  #ifdef PRAGMAMPWC
  #pragma mpwc off
  #endif /*PRAGMAMPWC*/
  #endif /*INFOFUN*/

  #ifdef powerc /*powerc defined means compiling for Power PC*/
  RoutineDescriptor USERFUNENTRY =
      BUILD_ROUTINE_DESCRIPTOR(uppMainEntryProcInfo04, USERFUN);
  RoutineDescriptor ARGINFOENTRY =
      BUILD_ROUTINE_DESCRIPTOR(uppArgInfoEntryProcInfo, ARGINFO);
  #endif /*powerc*/

In topic arginfo_fun is C code not using the macros in Userfun.h for
user function fooeval and its arginfo function arginfo_foo.  Here is C
code using the macros that should compile correctly on all platforms
using the C macros defined in Userfun.h.  Since fooeval calls back to
MacAnova, it must define MVCALLBACKS before including Userfun.h.  This
allows use of macros such as mvPrint and mvEval to call back to
MacAnova.  See topic callback_fun or header file Userfun.h for
information on type sprintftype.

File fooeval.c:
  #define MVCALLBACKS   /*enables call backs; required before include*/
  #include "Userfun.h"

  #ifndef MACINTOSH
  #define MAINFUN  /*if defined, compile fooeval*/
  #ifndef DJGPP
  #define INFOFUN  /*if defined, compile arginfo function for fooeval*/
  #endif
  #define USERFUN fooeval
  #define ARGINFO arginfo_fooeval
  #else /*MACINTOSH*/

  /*
      For PPC MAC, one function must be called main
      For 68K MAC, only one function is reachable per compilation
      project and it must be called main
  */
  #ifdef powerc
  #define MAINFUN
  #define INFOFUN
  #define main_fooeval main
  #else /*powerc*/
  /* define which of the 2 functions this project is for*/
  #define WHICHFUN 1

  #if WHICHFUN == 1
  #define MAINFUN
  #else
  #define INFOFUN
  #endif

  #if defined(MAINFUN)
  #define main_fooeval main
  #else
  #define main_info    main
  #endif

  #endif /*powerc*/
  #define USERFUN       main_fooeval
  #define USERFUNENTRY  fooeval
  #define ARGINFO       main_info
  #define ARGINFOENTRY  arginfo_fooeval

  #endif /*MACINTOSH*/

  #ifdef MAINFUN
  void EXPORTED USERFUN(CHARARG(commandarg), CALLBACKLIST(funlist))
  {
      char              **commandH = THECOMMAND(commandarg);
      Symbolhandle        result;
      char                line[200];
      sprintftype         sprintf; /*type defined in Userfun.h*/

      EnterCode();

      setMvFuns(funlist); /*initializes global duplicate of funlist*/

      sprintf = (sprintftype) mvFindfun("sprintf");

      result = mvEval(commandH);

      if (result != (Symbolhandle) 0)
      {
          switch (TYPE(result))
          {
            case CHAR:
              sprintf(line, "STRINGPTR(result) = '%s'", STRINGPTR(result));
              break;

            case REAL:
              if (!mvIsmissing(&DATAVALUE(result,0)))
              {
                  sprintf(line, "DATAVALUE(result,0) = %.17g",
                        DATAVALUE(result,0));
              }
              else
              {
                  sprintf(line, "DATAVALUE(result,0) = MISSING");
              }

              break;

            case LOGIC:
              sprintf(line, "DATAVALUE(result,0) = %c",
                      (DATAVALUE(result,0)) ? 'T' : 'F');
              break;

            case NULLSYM:
              sprintf(line, "Result is NULL");
              break;

            default:
              sprintf(line,
                "Type %ld of result not CHARACTER, REAL, LOGICAL, or NULL",
                TYPE(result))
          }
          mvPrint(line);
      }
      else
      {
          mvAlert("ERROR: Command produced error");
        /*tell User() error occurred but no message should be printed*/
          mvSeterror(silentCallbackError);
      }
      ExitCode();
  } /*fooeval()*/
  #endif /*MAINFUN*/

  #ifdef INFOFUN
  static long Fooevalarginfo[] =
        {1, DOESCALLBACK | POINTERUSE | NOSYMBOLARGS, CHARSCALAR};

  #ifdef PRAGMAMPWC
  #pragma mpwc on
  #endif /*PRAGMAMPWC*/

  long * EXPORTED ARGINFO(void)
  {
      long         *arginfo;

      EnterCode();

      arginfo = Fooevalarginfo;
      CHECK68881(arginfo);
      ExitCode();
      return(arginfo);
  }
  #ifdef PRAGMAMPW
  #pragma mpwc off
  #endif /*PRAGMAMPW*/

  #endif /*INFOFUN*/

  #ifdef powerc
  RoutineDescriptor USERFUNENTRY =
     BUILD_ROUTINE_DESCRIPTOR(uppMainEntryProcInfo02, USERFUN);
  RoutineDescriptor ARGINFOENTRY =
     BUILD_ROUTINE_DESCRIPTOR(uppArgInfoEntryProcInfo, ARGINFO);
  #endif /*powerc*/


Gary Oehlert 2003-01-15