Help file on user functions for use with MacAnova 4.05
(C) 2000 by Gary W. Oehlert and Christopher Bingham
Updated 20001003 CB

This file includes topics concerning the use, writing, and compiling
user functions for MacAnova.  It may be used as a MacAnova help file by
  Cmd> help(file:"Userfun.hlp")

or you can retrieve topics using macro userfunhelp.  Type userfunhelp()
for a list of topics.

Topics included are
  arginfo_fun       Description of the form arginfo functions; includes
                    example C code.
  c_macros          Description of macros in Userfun.h; includes
                    example C code.
  callback_fun      Description of user functions calling back
                    to MacAnova; includes example C code.
  compile_dos       Compiling DOS user functions
  compile_mac       Compiling Macintosh user functions
  compile_unix      Compiling Unix user functions
  compile_win       Compiling Windows user functions
  loadUser          Description of the use of MacAnova function
                    loadUser()
  type_codes        List of argument type and shape codes used by
                    arginfo functions
  User              Description of the use of MacAnova function User()
  userfunhelp       Macro to retrieve help from this file
  userfun_index     Annoted list of help entries in this file
  user_fun          Description of the form of a user function; includes
                    example C code.

A suggested order for reading them is
  loadUser
  User
  user_fun
  arginfo_fun
  callback_fun
  c_macros
  compile_dos compile_mac compile_unix compile_win
  type_codes

!!!! Starting marker for message of the day
!!!! Ending marker for message of the day

???? Starting marker for list of up to 32 comma/newline separated keys
Coding
Compiling
Executing
Loading
Sample source
User functions
???? Ending marker for keys

Note: There are no topics with names longer than 15 characters so as to
allow 5 column output from 'help()' with width >= 80.

This file is read by commands help() and usage() and macro userfunhelp.

Each topic starts with '====topicName' in column 1, followed by an
unlimited number of lines of information.  It is helpful, but not
required, that topics be in alphabetical order.  Topic names should, if
possible, be no longer than 12 characters, since otherwise they must be
quoted in a help() command.  The convention is used that when referring
to functions, but not macros, by name, '()' is appended.

Keys separated by commas can follow the topic name if separated from it
by '#'.  These should be selected from up to 32 keys listed between
lines starting with '????' somewhere before the first help topic.  Case
is ignored.

If the next line after '====topicName' starts with '%%%%', all following
lines up to a matching '%%%%' are skipped by help() and printed by
usage().  usage() skips the lines following the second '%%%%'.

The file should be terminated by a line starting '_E_O_F_'

====arginfo_fun#user functions,coding,sample source
%%%%
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.
%%%%
This topic presumes familiarity with topic User() and user_fun.  It
provides a brief introduction to the form of an arginfo function, that
is an externally compiled function that can be called by MacAnova to
obtain information about the arguments expected by a user function.  If
available, an arginfo function operates transparently to the user of
MacAnova.  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.

This topic presumes familiarity with topics user_fun and callback_fun.

Arginfo functions are not currently possible when compiling for the
protected mode DOS version (DJGPP).

Since we have no experience with writing arginfo functions in Fortran,
no Fortran related information is provided here.

In the following, 'handle' is used in the Macintosh OS sense, as a
pointer to a pointer.

To compile an arginfo function associated with user function foo, say,
you need to include a function named 'arginfo_foo' in the source for
foo.  arginfo_foo should have no arguments and should return a pointer
to a vector of long integers, that is it should be declared as
  long * arginfo_foo(void)
When compiling for Windows using Borland C/C++ 4.5, the declaration
should be
  long * _export arginfo_foo(void)

The ending of the name of the arginfo function (here 'foo') must match
the name of the user function.

arginfo_foo should return a pointer to a vector arginfo of Nargs + 2
long integers, where Nargs is the number of arguments expected by foo,
excluding the list, if any, of call back functions (see callback_fun).

The first element of vector arginfo (arginfo[0]) must be Nargs >= 1.

The second element of vector arginfo (arginfo[1]) is composed of bit
constants that specify various properties of the function (whether it
makes call backs, whether it expects pointers or handles, whether its
arguments should be data or symbols, and whether a required 68881
co-processor is absent (Macintosh only).  Symbolic names for these are
defined in header file dynload.h which is automatically included by
header file Userfun.h.
    Name of bit      Meaning
    DOESCALLBACK     Call backs to MacAnova functions will be made
    NOCALLBACK       No call backs to MacAnova functions will be made
    USESPOINTERS     Arguments should be pointers
    USESHANDLES      Arguments should be handles
    POINTERUSE       Same as USESHANDLES on Macintosh and same as
                     USESPOINTERS on other systems
    SYMBOLARGS       All arguments (except call back function list) are
                     pointers or handles to Symbols
    NOSYMBOLARGS     All arguments (except call back function list) are
                     pointers or handles to data
    COPROCESSOROK    Co-processor not needed or, if needed, is available
    COPROCESSORERROR A co-processor is needed but not available

For example, for a function with default pointer/handle usage that makes
call backs and does not expect Symbol arguments, arginfo[1] should be
DOESCALLBACK | POINTERUSE | NOSYMBOLARGS.  When compiling for a Macintosh,
this is equivalent to DOESCALLBACK | USERSHANDLES | NOSYMBOLARGS; when
compiling for other computers it is equivalent to DOESCALLBACK |
USESPOINTERS | NOSYMBOLARGS

Strictly speaking NOCALLBACK and NOSYMBOLARGS are not needed since they
evaluate to 0, but their use can make for clearer code.

The remaining Nargs elements (arginfo[2], arginfo[3], ...,
arginfo[Nargs+1]) of the vector are integers that specify the MacAnova
types of the user function arguments, using symbolic constants defined
in Userfun.h.  Typical constants are REALMATRIX, CHARSCALAR,
LOGICSCALAR, INTVECTOR, POSITIVEREALVECTOR, NONNEGATIVEINT, LONGVECTOR
and SYMHVALUE.  The qualifier INT means REAL with integer values; the
qualifer LONG means actual long integers as produced by asLong().  See
topic type_codes for a complete list of permissible constants.

In writing a function for a 68K Macintosh when compiling using
Metrowerks CodeWarrior, to ensure correct compilation, all declarations
of call back and arginfo functions must be bracketed by

  #pragma mpwc on
  ...
  #pragma mpwc off

Here is an example of a function to provide argument information for
fooeval() listed under topic callback_fun and executed from MacAnova by,
say,
  Cmd> User("fooeval", "sqrt(PI/2)")

Non-Macintosh version:
  #include "Userfun.h"

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

  long * arginfo_fooeval(void)
  {
      return(Fooevalarginfo);
  }

Macintosh version:

  #include "Userfun.h"

  #define info_main main

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

  #ifndef powerc
  #pragma mpwc on
  #endif
  long * info_main(void)
  {
      long         *arginfo;

      EnterCode();

      arginfo = Fooevalarginfo;
      /*add COPROCESSORERROR to arginfo[1] if appropriate*/
      CHECK68881(arginfo);

      ExitCode();
      return(arginfo);
  }
  #ifndef powerc
  #pragma mpwc off
  #endif

  #ifdef powerc
  RoutineDescriptor arginfo_fooeval =
     BUILD_ROUTINE_DESCRIPTOR(uppArgInfoEntryProcInfo, info_main);
  #endif /*powerc*/

When compiled for a 68K Macintosh, this must be compiled separately from
fooeval.  If the source is in the same file as source for fooeval, some
form of conditional compilation should be used so that both
arginfo_fooeval and fooeval don't both get compiled at once.  The code
resource produced should have name arginfo_fooeval and be included in
the same resource file as fooeval.

When compiled for a Power PC Macintosh, arginfo_fooeval would normally
be in the same source file as fooeval (C function main) and info_main
would not be defined to be main.  A single compilation would produce a
resource file containing resource fooeval with entries fooeval and
arginfo_fooeval.  The actual entry points would be specified by
RoutineDescriptors fooeval and fooeval_arginfo.

See topics compile_dos, compile_mac, compile_unix and compile_dos for
information on compiling a user function on different types of
computers.

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

See topic user_fun for information on the structure of a user function
not making call backs to MacAnova.

See topic callback_fun for information on the structure of a user
function making call backs to Macanova.

See topic c_macros and header file Userfun.h distributed with MacAnova
for C macros that are helpful in writing arginfo functions.

====c_macros#user functions,coding,sample source
%%%%
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.
%%%%
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*/

====callback_fun#user functions,coding,sample source
%%%%
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.
%%%%
This topic provides a brief introduction to the form of a user function
that makes "call backs" (executes functions internal to MacAnova).
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.

It presumes familiarity with topic user_fun which describes the
structure of user functions not making call backs.

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 arginfo_fun for information on how to make it possible for
MacAnova to obtain information about a user function for automatic
argument checking.

Since we have no experience in making call backs from a Fortran routine,
no Fortran tips are given.

In the following, 'handle' is used in the Macintosh OS sense, as a
pointer to a pointer.

          Structure of user functions calling back to MacAnova
In addition to regular arguments (pointers or handles to data or
symbols; see topic user_fun), a user function that calls back to
MacAnova must have an extra argument providing a list of functions that
can be called.  This is either a pointer (non-Macintosh) or handle
(Macintosh) to a MacAnovaCBS structure (defined in header file
dynload.h, included by header file Userfun.h).

Example of non-Macintosh declaration
  void fooclbck(char * m, MacAnovaCBS * funlist)
or
  void fooclbck(char * m, MacAnovaCBSPtr funlist)

Example of Macintosh declaration
  void fooclbck(char ** m, MacAnovaCBS ** funlist)
or
  void fooclbck(char ** m, MacAnovaCBSH funlist)

Here is the current definition of a MacAnovaCBS structure taken from
header file dynload.h:

  typedef struct MacAnovaCBS
  {
      void          (*print)(char *);
      void          (*alert)(char *);
      Symbol **     (*eval)(char **);
      long          (*ismissing)(double *);
      void          (*seterror)(long);
      void *        (*findfun)(char *);
  } MacAnovaCBS, *MacAnovaCBSPtr, **MacAnovaCBSH;

All the components are pointers to single argument functions internal to
MacAnova.

'print' points to mvPrint which expects a pointer to null terminated
character vector (a "string") as argument. It inserts the string in the
MacAnova output stream, usually the screen or command/output window.
Virtually all MacAnova output is printed with mvPrint.  If output is
being spooled to a file (see spool()), mvPrint correctly handles it.

'alert' points to mvAlert() which expects a pointer to a string as
argument.  In a windowed version (Macintosh, Windows, Motif), this
displays the string in a dialog box.  In other versions, 'alert' is
equivalent to 'print'.

'eval' points to mvEval which expects a handle to a character string
(type char **) as argument.  mvEval evaluates this string as if it were
input to MacAnova, almost as if it were the text of a macro, and returns
a handle of type Symbolhandle as value.  Just as in a macro, this is the
value of the last expression evaluated.  C macros in dynload.h allow
access to the type (REAL, CHARACTER, ...), dimension and value of the
value returned by mvEval.  The argument to mvEval must be a handle (char
**) even in a non-Macintosh user function.

'ismissing' points to mvIsmissing which expects a pointer to double
(double *) as argument.  If x is a pointer to a double vector,
mvIsmissing(&x[i]) (or mvIsmissing(x+i)) returns 1 if x[i] is MISSING
and 0 otherwise.

'seterror' points to mvSeterror which expects a long integer as
argument.  mvSeterror(code) sets a variable that will be checked by
User() on return.  If the value is non-zero User() treats it as an
error.  Unless code = silentCallbackError (defined whenever MacAnovaCBS
is defined), User will print the value.

'findfun' points to mvFindfun which expects a pointer to a string
containing the name of an internal MacAnova function as argument.
mvFindfun returns a pointer to void (C type void *) which must be cast
to a function pointer of the appropriate type.  A NULL return value
indicates the function could not be found.

On some systems, you may be able to access any function known to
MacAnova; on others, the available functions are limited to those in a
short list.  The functions available always include the following
functions that can be used to allocate and de-allocate memory and to
create and decode character strings.  Additional functions may be
available on other systems.

  char ** mygethandle(long n)             Allocate n bytes of memory
                                          and return handle to the
                                          space allocated
  void mydisphandle(char ** x)            De-allocate memory referenced
                                          by handle x
  char ** mygrowhandle(char **x, long n)  Allocate n bytes, copy at most
                                          n bytes of x to it and then
                                          de-allocate x.
  int sprintf(char * bf, char * fmt, ...) Formatted "print" to buffer bf
  int sscanf(char * bf, char * fmt, ...)  Formatted "scan" of buffer bf

C types for these functions are defined in header file Userfun.h so that
you can use the following to declare local pointers to them:

  mygethandletype      mygethandle;
  mydisphandletype     mydisphandle;
  mygrowhandletype     mygrowhandle;
  sprintftype          sprintf;
  sscanftype           sscanf.

See below for an example.

Memory management functions mygethandle, mydisphandle and mygrowhandle
work with handles (pointers to pointers) in all versions.

The char ** arguments to mydisphandle and mygrowhandle must have been
allocated by mygethandle.

On a Macintosh, although memory is allocated using Macintosh OS function
NewHandle, the values returned by mygethandle and mygrowhandle cannot be
used as handle arguments to Macintosh OS functions such as DisposHandle.

It appears that calling back to these sprintf and sscanf is the only way
to use them in the protected mode DOS version; in other versions, you
can probably use them directly.

In writing a 68K Macintosh user function, to ensure correct compilation,
all declarations of call back and arginfo functions must be bracketed by

  #pragma mpwc on
  ...
  #pragma mpwc off

This is because the released 68K versions of MacAnova are compiled using
MPW C.

Here is an example of a function that calls back to MacAnova.  It uses
mvEval to evaluate its first argument as a command and then uses call
back functions to print a message describing the result of the
evaluation.  A typical use might be User("fooeval","sqrt(2*PI)").

Non-Macintosh version:

  #include "Userfun.h"

  void fooeval(char * commandarg, MacAnovaCBSPtr funlist)
  {
      char              **commandH = &commandarg;
      Symbolhandle        result;
      char                line[200];
      void              (*mvPrint)(char *) = funlist->print;
      void              (*mvAlert)(char *) = funlist->alert;
      long              (*mvIsmissing)(double *) = funlist->ismissing;
      Symbolhandle      (*mvEval)(char **) = funlist->eval;
      void              (*mvSeterror)(long) = funlist->seterror;
      void             *(*mvFindfun)(char *) = funlist->findfun;
      sprintftype         sprintf;

      /* the code from here to END is the same for any version */
      sprintf = (sprintftype) mvFindfun("sprintf");

      result = mvEval(commandH); /* have MacAnova evaluate the command*/

      if (result != (Symbolhandle) 0)
      {
          /*
            C macros TYPE, STRINGPTR, DATAVALUE and constants
            CHAR, REAL, LOGIC, and NULLSYM are defined in Userfun.h
            along with other macros for working with Symbols
            */
          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 of result not CHARACTER, REAL, LOGICAL, or NULL");
          }
          mvPrint(line);
      }
      else
      {
          mvAlert("ERROR: Command produced error");
  /*Tell User an error has occurred but code should not be printed*/
          mvSeterror(silentCallbackError);
      }
      /* END */
  }

Macintosh version:

  #include "Userfun.h"
  /*
    On a Macintosh, the main entry must be called main;  the function
    is found by the name of its code resource
  */
  void main(char ** commandarg, MacAnovaCBSH funlist)
  {
      char              **commandH = commandarg;
      Symbolhandle        result;
      char                line[200];
  #ifndef powerc /*if compiled for 68K Macintosh*/
  #pragma mpwc on
  #endif
      void              (*mvPrint)(char *) = funlist->print;
      void              (*mvAlert)(char *) = funlist->alert;
      long              (*mvIsmissing)(double *) = funlist->ismissing;
      Symbolhandle      (*mvEval)(char **) = funlist->eval;
      void              (*mvSeterror)(long) = funlist->seterror;
      void             *(*mvFindfun)(char *) = funlist->findfun;
  #ifndef powerc
  #pragma mpwc off
  #endif
      EnterCode();
  /* the code from here to END is the same for any version */
      . . . . . . . . . . . see above . . . . .
  /* END */
      Exitcode();
  }

  #ifdef powerc /*powerc defined means compiling for Power PC*/
   RoutineDescriptor fooeval =
      BUILD_ROUTINE_DESCRIPTOR(uppMainEntryProcInfo02,main);
  #endif /*powerc*/

====compile_dos#user functions,compiling
%%%%
Type userfunhelp(compile_dos) for information on how to compile a user
  function for use with the protected mode DOS version of MacAnova.
%%%%
This topic provides some details about compiling a user function for use
with the protected mode DOS version of MacAnova.  User functions are not
implemented in the real mode version (BCPP).  Compilation uses version
2.0 of the DJGPP compiler.

DJGPP uses the dxe format for loading.  This is a simple but restricted
method of loading.  In particular, you can access only one entry point
(function) in a file. You should compile the file with gcc as usual as
in
  gcc -c goo.c subs.c
and then run dxegen (supplied with DJGPP 2.0) as in
  dxegen goo.dxe _goo goo.o subs.o -lm -lc

The first two arguments to dxegen are the output file and the entry
point to be made visible for loading (note the prepended underscore).
These are followed by the compiled (*.o) files and arguments specifying
libraries to be searched.

There are some restrictions on your source file.  Not all library
functions may be used.  Excluded functions include input/output
functions and their relatives such as sprintf and sscanf.  In addition
there are some naming restrictions.  For example, you can't have
functions foo and foo2 and try to load entry point _foo, but you could
have foo and dofoo (it seems that the leading string must be unique).

Because sprintf and sscanf are frequently needed, (sprintf is often
used to build output lines or error messages), they are included in the
list of functions known to mvFindfun.

Because you can have only one entry point using dxe files, you cannot
also provide arginfo_foo() to check the number and types of arguments.
Moreover, you must use 'callback:T' and/or 'symbols:T' on User() when
executing a user function that makes call backs and/or expects
Macanova symbols as arguments.

====compile_mac#user functions,compiling
%%%%
Type userfunhelp(compile_mac) for information on how to compile a user
  function for use with Macintosh versions of MacAnova.
%%%%
This topic provides some details about compiling a user function for use
with the Macintosh versions of MacAnova.  It assumes the Metrowerks
CodeWarrior compiler is used.

The Macintosh is a bit more complicated than other platforms, since
there are two kinds of processors (PPC and 68K) to support.  The 68K
case is further complicated by the fact that code may or may not
compiled to use a 68881 math coprocessor.

In coding a Macintosh user function, 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 been changed by the call back.

User functions and arginfo functions are compiled into code resources
in files of type 'rsrc'.  PPC resources must have resource type
'MVPP'; 68K resources not requiring a 68881 coprocessor must have
resource type 'MV6n'; and 68K resources requiring a coprocessor must
have resource type 'MV6c'.

User() accesses the resources themselves by name.  The resource for a
function should have the name, say 'foo', you will give in your User()
call or 'arginfo_foo.  All resources of the same type should in a file
should have distinct resource numbers, say 4000, 4001, ... .  A PPC user
function may be in a resource with a different name, in which case you
have to provide the name of the resource using User(funName,
resource:resName, ...).

Source files for both PPC and 68K user functions must have a function
named 'main', plus possibly other functions.

PPC code resources, but not 68K ones, can have additional entry points,
usually an arginfo function, but occasionally other user functions.

                      Macintosh 68K user functions
For 68K user functions, it is necessary to set 68000 register A4 so
that global variables will be found.  Using CodeWarrior, this is
accomplished by including
  EnterCodeResource();
immediately after declaring local variables and before any reference
to global variables, and including
  ExitCodeResource();
immediately before returning.  When C macro MACINTOSH is defined but
powerc is not, macros EnterCode() and ExitCode() defined in header file
Userfun.h expand to EnterCodeResource() and ExitCodeResource().
Otherwise they expand to nothing.

68K code resources have just one entry point which must be named
'main', so a single resource cannot include both a user function and
its arginfo function.  However, the Codewarrior compiler has a "Merge
to file" option that allows you to add to an existing resource file
the resource created when compiling a function.

                           PPC User Functions
PPC code resources may have multiple entry points which are taken from
the names of global RoutineDescriptor variables in the source.  Their
names should similar to 'goo' and 'arginfo_goo' or 'fooeval' and
'arginfo_fooeval'.  The name given to the function that actually codes
the user function should be 'main' and the name given to the function
with the arginfo function code should be something like 'main_info'
different from the name given to the arginfo.  Here are typical
RoutineDescriptor declarations.

  RoutineDescriptor goo =
      BUILD_ROUTINE_DESCRIPTOR(uppMainEntryProcInfo04, main);
  RoutineDescriptor arginfo_goo =
     BUILD_ROUTINE_DESCRIPTOR(uppArgInfoEntryProcInfo, info_main);

Argument uppMainEntryProcInfo04 is appropriate for a user function
expecting 4 arguments, including the call back function list.  For a
function expecting 5 arguments, use uppMainEntryProcInfo05, and so on.

Since you will normally use the funName given in the User("funName",...)
call for both the name of the resource and the name of the
RoutineDescriptor entry point, you will ordinarily include only one user
function (and its arginfo function) in a resource.  If you include more
than one user function in a resource, you must use keyword phrase
'resource:Resname' to specify the resource name.  An arginfo function
must be in the same resource as its user function.

                   Setting up Macintosh 68K projects
Here is how to set things up to create a 68K code file with resources
'fooeval' and 'arginfo_fooeval' based on file fooeval.c listed in topic
c_macros.  This has been written in such a way that only one of fooeval
or arginfo_fooeval will be compiled, depending on the value of C macro
WHICHFUN.

(1) Create two MacOS 68K CodeWarrior project files, one for fooeval and
the other for arginfo_fooeval.  They should both have source files
fooeval.c, Userfun.h and dynload.h.  See below for library files needed.

(1.a) Specify Code Resource for the project type for both projects.

(1.a) For both projects specify resource type 'rsrc' and the same resource
file, say, Fooeval.rez as Project options.  The fooeval project should
specify 'fooeval' and 4000 as the resource name and number.  The
arginfo_fooeval project should specify 'arginfo_fooeval' and 4001 as the
resource name and number, and should have Merge to File checked.  The
resource numbers are arbitrary but should be different.  The resource
type should be 'MV6c' or 'MV6n', depending on whether you are compiling
to use a 68881 math coprocessor.

(1.b) Both projects should specify processor options 68020 Codegen, 4 byte
ints, 8 byte doubles and far data.  If you are compiling to use a math
coprocess, also specify 68881 Codegen,

(1.c) Set linker options Link Single Segment.

(1.d) For a user function making call backs (as does fooeval), C/C++
language option MPW Newlines should be checked.

(1.e) If you reference any C library functions such as strcpy (fooeval
does not) you will need library file 'ANSIFa(N/4i/8d)C.A4.68K.Lib' and
possibly 'MathLib68K Fa(4i/8d).A4.Lib' ('ANSIFa(N/4i/F/8d)C.A4.68K.Lib'
and 'MathLib68K Fa(4i/f/8d).A4.Lib' if compiling to use a 68881 math
comprocessor).  You may also need MacOS.lib.  For example, all three
libraries are needed if you use the library version of sprintf.  None is
required for fooeval.c as written.

(1.f)  Both projects should specify a prefix file, say Userfun.pch,
containing at least the following:
 #define MACINTOSH
 #define MW_CW

(2) Edit fooeval.c to define C macro WHICHFUN as 1 and compile the
fooeval project.

(3) Re-edit fooeval.c to define WHICHFUN as 2 and compile the
arginfo_fooeval project.

You end up with one resource file 'Fooeval.rez' containing resources
'fooeval' and 'arginfo_fooeval'.

                   Setting up Macintosh PPC projects
Here is how to set up a CodeWarrior project to compile a PPC version of
fooeval using source file fooeval.c listed in topic c_macros.

(1)  Create a MacOS PPC project with source files fooeval.c, Userfun.h
and dynload.h and library files MPCRuntime.Lib and InterfaceLib.  See
below for other library files.

(1.a) Specify Code Resource for the project type

(1.b) Specify resource file 'fooevalppc.rez' of type 'rsrc'.  The
resource type must be 'MVPP'.  The resource name should be 'fooeval'.
The resource number should be different from any other PPC user
functions you might be using simultaneously.

(1.c) Specify Main entry 'main' for the PPC linker.

(1.d) For a user function making call backs (as does fooeval), C/C++
language option MPW Newlines should be checked.

(1.e) If you reference any C library functions such as strcmp you should
add libraries 'ANSI C.PPC.Lib' and 'MathLib' and file 'console.stubs.c'.

(2) Compile the fooeval PPC project.

You end up with a resource file fooevalppc.rez containing resource
'foo'.  You load it into MacAnova by loadUser("fooevalppc.rez") and
execute it by, say, User("fooeval","exp(-x^2/2)/sqrt(2*PI)").

====compile_unix#user functions,compiling
%%%%
Type userfunhelp(compile_unix) for information on how to compile a user
  function for use with a Unix version of Macanova, including Motif.
%%%%
This topic provides some details about compiling a user function to be
used with a Unix version of MacAnova (including Unix Motif).

                       Hewlett-Packard UX (HPUX)
The file to load must be a shared library.  This can be constructed, for
example, by
  cc -c +z -Aa fooeval.c
  ld -b fooeval.o -o fooeval.sl
It should be loaded by loadUser("fooeval.sl").

At present (version 4.05 release 1), there may be unsatisfied external
problems when linking with system libraries.

                          Other Unix Versions
Compilation and linking commands may be different.  MacAnova will have
to have been compiled and linked with functions for using a shared
library.  The actual loading of shared libraries and execution of
routines in them is done in file dynload.c.  Currently (July 1997) this
has been coded only for HPUX (using shl_load() and shl_findsym()).  Most
Unix versions will have similar functions.  For example, on IRIX, the
corresponding functions are dlopen() and dlsym().

====compile_win#user functions,compiling
%%%%
Type userfunhelp(compile_win) for information on how to compile a user
  function for use with the Windows version of MacAnova.
%%%%
This topic provides some details about compiling a user function using
Borland C/C++ for use with the Windows version of MacAnova.

Set up the project to construct a 32 bit DLL.

Change the default Project Options as follows:
  Add WIN32 to the list of defines
  Set 32-bit Compiler Processor Data Alignment to Quad word (8 bytes).
  Set Resources Target Windows Version to Win32

In the source, add the modifier "_export" to the functions in the
project, as in
  void _export goo(double *x, double *y, long *n, double *result)
  long * _export goo_arginfo(void)

This will be accomplished automatically if you include header file
Userfun.h, and preface routine names with EXPORTED instead of _export.

Entry names will be prefixed by the compiler with '_'.  For this reason,
User("_foo", ... ) and User("foo", ... ) are equivalent.

Files goo.c and fooeval.c listed in topic c_macros are examples of user
functions that compile for Windows.

====loadUser#user functions,loading
%%%%
loadUser(fileName [,reload:T or clear:T]), CHARACTER scalar fileName.
%%%%
loadUser(FileName) loads a user function (separately compiled routine)
into MacAnova.  FileName should be a quoted string or CHARACTER scalar
giving the name of the file containing the user function to be loaded.
Once loaded, a user function can be executed by function User().  As
usual, in windowed versions (Macintosh, Windows, Motif), FileName can be
"".  If the file has been previously loaded, it is not reloaded, but it
may be put at the start of the entry search list for the next use of
User().

loadUser(FileName, reload:T) does the same, except that the file will be
reloaded, even if it has been previously loaded into MacAnova.

loadUser(FileName, clear:T) does the same, except all previously loaded
files will be forgotten.

On some systems, the user function can be written in Fortran, although
some features such as call back functions and argument checking may not
be available.

Functions loadUser() and User() are inherently specific to a particular
computer system although it is possible to write user functions that can
be compiled on multiple systems without change.

Unix:
  FileName must be the name of a shared library.
Windows:
  FileName must be the name of a DLL.
Protected mode DOS (DJGPP):
  FileName must be the name of a dxe file.
Macintosh:
  FileName must be the name of a file containing one or more code
  resources.  The PPC version of MacAnova can call both 68K and PPC code
  resources, but a 68K version of MacAnova can call only 68K code
  resources.  Resource types must be one of 'MVPP' (PPC), 'MV6n' (68K
  without coprocessor) or 'MV6c' (68K with coprocessor).

See also topics User() and user_fun.  Type userfunhelp(User) or
userfunhelp(user_fun).

====type_codes#user functions,coding
%%%%
Type userfunhelp(type_codes) for a complete list of argument type and
  shape codes to be returned by an arginfo function.
%%%%
This topic lists the type and shape codes that may be used by an arginfo
function to provide information about the arguments expected by a user
function (see topic arginfo_fun).  They are all integer constants
defined in header file Userfun.h.

Scalar argument (all dimensions 1)
  CHARSCALAR, LOGICSCALAR, REALSCALAR, NONMISSINGREAL, POSITIVEREAL,
  NONNEGATIVEREAL, INTSCALAR, POSITIVEINT, NONNEGATIVEINT, LONGSCALAR,
  POSITIVELONG, NONNEGATIVELONG

Vector argument (all dimensions beyond first, if any, are 1)
  CHARVECTOR, LOGICVECTOR, REALVECTOR, NONMISSINGREALVECTOR,
  POSITIVEVECTOR, NONNEGATIVEVECTOR, INTVECTOR, POSITIVEINTVECTOR,
  NONNEGATIVEINTVECTOR, LONGVECTOR, POSITIVELONGVECTOR,
  NONNEGATIVELONGVECTOR

Matrix argument (no more than 2 dimensions >= 1)
  CHARMATRIX, LOGICMATRIX, REALMATRIX, NONMISSINGREALMATRIX,
  POSITIVEMATRIX, NONNEGATIVEMATRIX, INTMATRIX, POSITIVEINTMATRIX,
  NONNEGATIVEINTMATRIX, LONGMATRIX, POSITIVELONGMATRIX,
  NONNEGATIVELONGMATRIX

Square matrix argument
  REALSQUAREMATRIX

Array argument
  CHARARRAY, LOGICARRAY, REALARRAY, NONMISSINGREALARRAY, POSITIVEARRAY,
  NONNEGATIVEARRAY, INTARRAY, POSITIVEINTARRAY, NONNEGATIVEINTARRAY,
  LONGARRAY, POSITIVELONGARRAY, NONNEGATIVELONGARRAY

Arbitrary Symbol argument
  SYMHVALUE

The qualifiers INT, POSITIVE and NONNEGATIVE imply all elements must be
non-MISSING.

These codes are applicable both for user functions whose arguments are
pointers or handles to data, and for user functions whose arguments are
pointers or handles to MacAnova symbols.  SYMHVALUE should only be used
when symbol arguments are expected and then only when the argument is
not restricted to one type and shape or may has type different from
REAL, LOGICAL, CHARACTER or LONG.

====User#user functions,executing
%%%%
User(funName [,resource:resName][,control keyword phrases],arg1 [,...]),
  funName and resName CHARACTER scalars; control keyword phrases are any
  of callback:T, symbols:T, pointers:T and quiet:T; arg1, ... arguments
  to a user function; if argument is keyword phrase other than
  'protect:arg', it is returned, possibly modified.
%%%%
User(FuncName, arg1, arg2, ...) executes a user function, that is, a
compiled routine external to MacAnova.  Quoted string or CHARACTER
scalar FuncName specifies the name of a user function whose code is in a
file previously loaded by loadUser().  arg1, arg2, ... are arguments
that will be passed to the function.  You must have a least one argument
in addition to FuncName and no more than 20 (13 in the Macintosh PPC
version).  Depending on the compiler and system, you may be required to
include leading or trailing underscore characters '_' in FuncName, say
User("foo_",...) or User("_foo", ...) instead of User("foo", ...).

A 68K version of MacAnova cannot execute a user function compiled for a
PPC.

User(FuncName, quiet:T, arg1, ...) does the same except warning
messages, if any, are suppressed.

User(FuncName, callback:T, arg1, ...) specifies the function is known to
"call back" to MacAnova, that is, to execute functions internal to
MacAnova.  On a Macintosh, the type of user function (PPC or ordinary
68K) must match the version of MacAnova.  See topic 'callback_fun' in
file userfun.hlp (type userfunhelp(callback_fun)).

If the MacAnova version requires a 68881 math coprocessor, there can be
problems if a user function that makes call backs does not require a
coprocessor.

User(FuncName, symbols:T, arg1, ...) specifies that all the arguments
are to be passed as complete MacAnova "symbols", including all dimension
information.  This should be used only with a user function specifically
written to make use of MacAnova symbols.

The PPC Macintosh version cannot pass symbol arguments to a 68K user
function.

User(FuncName, pointers:T or F, arg1, ...) changes the default way
arguments are passed, either as "pointers" (pointers:T) or as "handles"
(pointers:F).  On all but Macintosh computers, the default is
pointers:T.  You are unlikely ever to need to use this keyword.

User(FuncName, resource:ResName, arg1, ...) specifies the name of the
PPC Macintosh resource containing the user function.  This option is not
needed in other versions and needed on a PPC only when the resource name
differs from the function name.

You can use more than one of the preceding keywords phrases together
(User("goo", resource:"foo",quiet:T,callback:T,x,result:0)).

On most systems, it is possible to include with a user function an
"arginfo" function that MacAnova can call to obtain information about
the user function.  The information includes the number of arguments
expected, their types and shapes expected (for example, CHARACTER
scalar, REAL matrix), and whether the function makes call backs or
expects "symbol" arguments (see above).  This allows automatic argument
checking.  If the function is compiled without an arginfo function,
using the wrong number or type of arguments will usually result in a
crash or other undesirable behavior.  In particular, a user function
will not be able to handle MacAnova symbol arguments unless it has been
specially written to be able to understand their structure.

You normally do not need to use keywords 'callback', 'symbols' and
'pointers' if the user function has an associated arginfo function which
is possible on all systems except protected mode DOS.

See topics user_fun and arginfo_fun in help file userfun.hlp for
information about the form of a user function and an arginfo function
(type userfunhelp(user_fun), say).

                       Interpretation of FuncName
Unix, Motif and Windows:
  FuncName should be the name of the function being called, possibly
  modified by a leading or trailing '_' (leading '_' when compiling for
  Windows with Borland C 4.5).  In Windows and Unix versions where it is
  known entry names start with '_', when the function is not found using
  the name as provided, a second search is made after prepending '_' to the
  name.  Thus if User("_foo", ...) would be successful, so will be
  User("foo", ... ).

Extended memory DOS (DJGPP):
  FuncName should be the same as the name of the .dxe file loaded by
  loadUser() that contains the code except that directory information
  and the extension ".dxe" may be omitted.  Thus after
  loadUser("../foo.dxe"), you can use any of User("../foo.dxe",...),
  User("foo.dxe",...) or User("foo",...).  When there is more than one
  file with the same name attached (for example, "/a/foo.dxe" and
  "/b/foo.dxe", you should use the complete path name.

PPC Macintosh user function
  FuncName is the name of the user function.  This will usually also be
  the name of the PPC code resource containing the user function.  If it
  is not, you need to include keyword phrase 'resource:ResName' as an
  argument, where ResName is a quoted string or CHARACTER scalar
  specifying the resource name.

68K Macintosh user function:
  FuncName should be the name of the 68K code resource containing the
  user function (only one user function per resource).  If
  'resource:ResName' is an argument, ResName must be identical with
  FunName.  It is an error to attempt to call a 68K user function that
  requires a 68881 or 68882 math coprocessor on a Macintosh without
  one.

                        User function arguments
All arguments except the function name and 'callback', 'quiet',
'symbols', 'pointers' and 'resource' keyword phrases are passed to the
user function as its arguments

Only copies of keyword phrase arguments are passed to a user function.
This means that the user function can modify these arguments without
danger of changing any MacAnova variable.

Non-keyword phrase arguments to User() (except the user function name)
are passed to the user function without being copied.  When the argument
is a named MacAnova variable and the user function modifies it, the
value of the variable itself is changed.  When the argument is a
literal number (User("foo", 1, 2, 0)) or expression (User("foo",
sqrt(2)+3, log(4), 19^2)) the function can safely change the argument
without danger to any variable.

Example:
Suppose fooadd expects three arguments, and modifies the third by
assigning the sum of the first two.  Then

  Cmd> c <- 0; User("fooadd", 1, 2, c)

returns no value (actually a NULL; see NULL), but c has been changed to
3 (= 1+2).  However,

  Cmd> c <- 0; User("fooadd", 1, 2, protect:c)

will not change c itself, but only a copy.

In addition to being copied before use, all keyword phrase user function
arguments are returned, possibly modified, as the value of User().  When
there are two or more such keyword arguments, a structure is returned
with component names taken from the keyword names.

Keyword 'protect' is special, in that its only effect is to cause its
value to be copied before being passed to the user function; its value
is not returned by User().  Thus the use of 'protect' in the example
makes the user function useless: c does not get changed because it is
protected by a keyword, but the modified value is not returned either.
The following both protects c and causes the modified value of the last
argument to be returned as the value of User().

  Cmd> c <- 0;User("fooadd", 1, 2, result:c)

This returns 3 = 1 + 2, but c would be unchanged.  In place of variable
c for result, you could use any REAL scalar (result:0).  This serves to
provide space for the answer.

  Cmd> User("fooadd", left:1, right:2, result:0)

returns a structure with components 'left', 'right' and 'result'
containing the possibly modified values of the original arguments.

It is essential that the size of any argument that is to be modified
matches the size that is expected by the user function.  Thus, if foocat
is a user function that concatenates its first two arguments into a
third argument, the length of the third argument should be the combined
length:

  Cmd> User("foocat", run(4), run(7), combined:rep(0,11)

In this example, for the third argument to have fewer than 11 elements
would lead to unpredictable results, possibly even a crash of MacAnova.

Except when symbols:T is an argument, all user function arguments are
either REAL, LOGICAL, CHARACTER or LONG variables.  REAL arguments are
passed as double precision data, as are LOGICAL arguments (True = 1.0,
False = 0.0).  When an argument is a matrix or array, the values are
ordered such that the first subscript changes fastest.  See topic
'user_fun' in help file userfun.hlp for more information (type
userfunhelp(user_fun)).

LONG is a special MacAnova type whose values are long integers between
-2147483647 and 2147483647 = 2^31 - 1.  A LONG argument can be created
only by function asLong().  A LONG argument that is returned
(result:asLong(x)), is turned into an REAL quantity before being
returned.  See asLong().

  Cmd> User("goo", run(10), run(10), asLong(10), result:0)

invokes user function goo with three REAL arguments and one long
argument.

For virtually unlimited flexibility, when keyword phrase 'symbols:T' is
an argument to User(), all user function arguments are passed as symbols
-- MacAnova objects which encapsulate the data, type, and dimensions of
a variable.  Thus

  Cmd> User("foo", symbols:T, x, y, result:z)

passes x, y and z to 'foo' as symbols.  You cannot have some user
function arguments be symbols and some just data; all must be symbols or
none.

====userfunhelp()#general
%%%%
userfunhelp(topic1 [, topic2 ...] [,usage:T] [,scrollback:T])
userfunhelp(key:Key), CHARACTER scalar Key
userfunhelp(index:T [,scrollback:T])
%%%%
userfunhelp(Topic1 [, Topic2, ...]) prints help on topics Topic1,
Topic2, ... related to user functions.  The help is taken from file
Userfun.mac.

userfunhelp(Topic1 [, Topic2, ...] , usage:T) prints usage information
related to these topics.

userfunhelp(index:T) or simply userfunhelp() prints an index of the
topics available using userfunhelp.

In all three usages, you can also include help() keyword phrase
'scrollback:T' as an argument to userfunhelp.  In windowed versions,
this directs the output/command window will be automatically scrolled
back to the start of the help output.

userfunhelp(key:key) where key is a quoted string or CHARACTER scalar
lists all topics cross referenced under Key.  userfunhelp(key:"?")
prints a list of available cross reference keys for topics in the file.

userfunhelp is implemented as a predefined macro.

See help() for information on direct use of help() to retrieve
information from Userfun.hlp.

====userfun_index*#
%%%%
Help topics in this file are arginfo_fun, c_macros, callback_fun,
compile_dos, compile_mac, compile_unix, compile_win, loadUser,
type_codes, User, userfun_index, and user_fun.  Th
%%%%
This file includes topics concerning the use, writing, and compiling
user functions for MacAnova.  You can retrieve help by, for example,
  Cmd> userfunhelp(User)

Topics in this file are
  arginfo_fun       Description of the form arginfo functions; includes
                    example C code.
  c_macros          Description of macros in Userfun.h; includes
                    example C code.
  callback_fun      Description of user functions calling back
                    to MacAnova; includes example C code.
  compile_dos       Compiling DOS user functions
  compile_mac       Compiling Macintosh user functions
  compile_unix      Compiling Unix user functions
  compile_win       Compiling Windows user functions
  loadUser          Description of the use of MacAnova function
                    loadUser()
  type_codes        List of argument type and shape codes used by
                    arginfo functions
  User              Description of the use of MacAnova function User()
  userfunhelp       Macro for retrieving help from Userfun.hlp
  userfun_index     This help item
  user_fun          Description of the form of a user function; includes
                    example C code.


====user_fun#user functions,coding,sample source
%%%%
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.
%%%%
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.


_E_O_F_#This should be the last line, an internal End Of File marker
