Next: Search Key Tables Up: User Function Help File Previous: userfunhelp()   Contents

user_fun

Usage:
Type userfunhelp(user_fun) for information on the structure of user
  functions.
Type userfunhelp(callback_fun) for information on the structure of user
  functions making "call backs" to MacAnova.
Type userfunhelp(arginfo_fun) for information on how to enable automatic
  checking of arguments to a user function.



Keywords: user functions, coding, sample source
This topic provides a brief introduction to the form of a user function
(routine compiled separately from MacAnova) that can be loaded by
loadUser() and executed by User().  Because of the inherent dependence
on the computer and operating system, there are many details that are
not covered here.  Additional details may be found in topics
compile_dos, compile_mac, compile_unx and compile_win.

See headerfile Userfun.h distributed with MacAnova for C macros that are
helpful in writing user functions.

See loadUser() and User() for information on how to load and execute a
user function.

See topic callback_fun for information on the structure of a user
function that makes call backs to Macanova.  It presumes familiarity
with this topic (user_fun).

See topic arginfo_fun for information on how to make it possible for
MacAnova to obtain information about a user function for automatic
argument checking.

On some systems, if you are willing to forego automatic argument
checking, creating a user function file may be as simple as recompiling
and linking existing code with certain options set.  On others you may
need to modify the code to include C header file Userfun.h which defines
various constants and C macros.  You will almost certainly need to use
Userfun.h if you write a user function that makes call backs (executes
routines internal to MacAnova) or provides argument checking capability.

                      Structure of a user function
Most of this discussion assumes the user function is written in C
although a few tips are given for user functions written in Fortran.  If
you write a user function in Fortran, you need to be aware that all its
arguments are pointers, that is the function receives the location in
computer memory of each argument, not its value.

Header file Userfun.h should normally be included in the C source,
especially if you expect that the user function will be compiled for
more than one computer type.  Userfun.h not only contains information
that may be essential for compilation (including type declaration for
symbols; see above), but also contains many C macros that make coding
easier.  In particular, it contains macros allowing you to write a user
function that may be compiled with little or no change on Unix,
Macintosh and Windows.  However, to make clear the principles, the
structure of a user function is illustrated without using these macros.

Note: Header file Userfun.h itself includes header dynload.h which is
also distributed with MacAnova.  Both need to be available when
compiling a user function.

Value returned:
  The user function should not return a value (C type void, Fortran
  subroutine).

Non-Macintosh argument types
  Each user function argument must be declared as a pointer.  The legal
  types are double * (REAL or LOGICAL data), char * (CHARACTER data),
  long * (LONG data), or Symbol * (symbol argument).  For Fortran, these
  are double precision, character and integer*4 (symbol not possible).

Example of non-Macintosh declaration:
  C:
   void goo(double * x, double * y, long * n, double * result)

  Fortran:
   subroutine goo(x, y, n, result)
   integer*4  n
   double precision  x(n), y(n), result

Macintosh argument types
  Each argument must be declared as a pointer to a pointer, known to
  Macintosh programmers as a "handle".  Thus the legal types are double
  ** (REAL or LOGICAL data), char ** (CHARACTER data), long ** (LONG
  data), or Symbol ** (symbol argument.  Type Symbolhandle declared in
  Userfun.h is equivalent to Symbol **.

  It is probably not possible to do this directly in Fortran.  A C
  interface to the Fortran subroutine will be required.

Example of Macintosh declaration:
  void goo(double ** x, double ** y, long ** n, double ** result)

  When "handle" is used below, it always means a pointer to a pointer,
  not any of the various handles used when programming for Windows.

  The reason for the use of handles as arguments to functions is that
  MacAnova functions may allocate memory.  On the Macintosh, this can
  move the contents of previously allocated memory, so that a pointer
  would no longer be valid.  However, the handle remains valid even if
  the pointer it points to changes.

  If you make a pointer by dereferencing a handle argument, you should
  dereference it again after calling back to a function internal to
  MacAnova since its location in memory may have changed.

Executable statements
  There should be no direct input or output statements (you can do
  output using a callback function) or any direct memory allocation
  (also possible using a callback function).  On a Macintosh, code must
  take into account the extra level of indirection of the handle
  arguments.

Here is C code for an example user function that computes the inner
product of two real vectors.

Non-Macintosh version:
  C:
  #include "Userfun.h" /*not needed here as coded*/

  void goo(double * x, double * y, long * n, double * result)
  {
      int         i;

      *result = 0.0;
      for (i = 0; i < *n; i++)
      {
          *result += x[i]*y[i];
      }
  }

  Fortran:
        subroutine goo(x, y, n, result)
        integer*4        n
        double precision x(n), y(n), result
        integer*4        i

        result = 0.0d0
        do 2 i = 1, n
          result = result + x(i)*y(i)
  2     continue
        return
        end

In Windows, when compiling using Borland C/C++ 4.5, you need to replace
"void goo" by "void _export goo".

Macintosh (both PPC and 68K) version:
  #include "Userfun.h" /* required */
  #define main_goo main /*entry must have internal name 'main'*/

  void main_goo(double ** argx, double ** argy, long ** argn,
           double ** argresult)
  {
      double     *x = *argx, *y = *argy, *z = *argz;
      long       *n = *argn;
      int         i;

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

  #ifdef powerc /*powerc defined means compiling for Power PC*/
   RoutineDescriptor goo =
      BUILD_ROUTINE_DESCRIPTOR(uppMainEntryProcInfo04,main_goo);
  #endif /*powerc*/

The first executable statement in a 68K Macintosh user function must be
EnterCodeResource(), and the last before the return must be
ExitCodeResource().  EnterCode() and ExitCode() are C macros defined in
Userfun.h that expand to these statements in a 68K Macintosh compilation
and to nothing in a PPC, DOS, Windows, Motif, Unix or other
compilation.

When coding for a PPC Macintosh, an additional statement declaring and
initializing a RoutineDescriptor is required for each function.
Constant uppMainEntryProcInfo04 is defined in dynload.h (automatically
included by Userfun.h) and is appropriate for a function with 4
arguments.


Gary Oehlert 2003-01-15