====================== RexxHost.Library v37.1 ========================

[ I had to fix a bug in rexxhost.library but could not remake the library
   with my Manx compiler. So I have changed the code so that it is a
   set of normal C functions which are linked in with each program.
      Pete Hardie
      VE5VA
]

======================================================================
An Amiga shared library for creating/managing ARexx host environments.
======================================================================

========================== IMPORTANT NOTICE ==========================
======================================================================
This is the official new release of rexxhost.library.  Due to register
rearrangements  programs compiled using the old 1.6 release have to be
recompiled  or  serious  system  crashes  will  result!  Note that the
supplied library code can only be recompiled under Aztec 'C' 5.0.

============================= Background =============================
======================================================================
A  friend  of mine was busy developing a stock management program when
he suddenly realized that an ARexx interface would be the only feature
that wasn't already part of his project.  So he started to analyze, to
program,  to  try - just to find out that it would be too much work to
add it.
        Some  months later a programmer who works for the same company
I  am  working  for decided to rewrite his home-brewn assembler/linker
program  to  interface to CygnusEd Professional.  The problem is:  his
program  is written in assembly language, the standard host management
routines are written in 'C'...
        To  simplify  the host creation/management procedure I decided
to  put  the  required  routines  and  some  extra  code into a shared
library,  easy  to  use  by  ANY  language (can you imagine AmigaBASIC
controlling AmigaTeX?).
        As  soon  as the Aztec 'C' 5.0 update came in, the library has
been  updated  to  take  advantage  of  the  new compiler features.  I
suppose  the  source  code  can  be  seen  as  a  real  'treasure' for
programmers  who also wish to build shared libraries with the new Manx
compiler but find the original Manx support code a bit too confusing.

============================= How to use =============================
======================================================================
The  rexxhost.library needs ARexx (any version will do, v1.10 is best)
to  work properly.  It needs to be opened EXPLICITELY, i.e.  it is not
forced  into  memory by the ARexx server and CANNOT be loaded with the
ADDLIB() call in rexx-scriptfiles.  An unlimited number of callers may
open   the   library,   it   is   100%   reentrant.    Just  like  the
rexxsyslib.library   the   rexxhost.library   stays  in  memory  until
explicitely expunged (e.g.  via "flushlibs" call from Workbench).
        The  OpenLibrary()  call  returns  a pointer to a RexxHostBase
structure (as defined in the rexxhostbase.h include file).  It has the
following format:

                struct RexxHostBase
                {
                        struct Library   LibNode;
                        struct RxsLib   *RexxSysBase;
                };

The  pointer  to the RxsLib structure represents a pointer to the base
of  rexxsyslib.library.   It  can  be  copied  by the calling process,
rexxsyslib.library does not need to be opened explicitely.
        All library functions are "bullet proof", i.e. if the supplied
arguments  are  illegal  the  functions return immediately.  Note that
this  library  only  contains  basic support functions, you will still
have  to  do  command analysis, parsing and command processing on your
own (which isn't difficult, look at the DClockHandler.c sourcecode for
an example).

============================= Compiling ==============================
======================================================================
A  Makefile  for  Aztec  'C'  5.0 is supplied.  This version CANNOT be
recompiled under compiler versions previous to 5.0.  Note that line 67
in the ARexx 'C' include file 'rxslib.h' has to be changed from:

        WORD rl_NumMsg; /* pending count */

to:

        WORD rl_PgmMsg; /* pending count */

or  you  will  get  a 'multiple entry' message from the compiler (Bill
obviously overlooked the misspelled entry).  In order to recompile the
library the following symbol must be defined in your header files:

        #define AG_CloseLib     0x00090000

The  linker  requires  a  library  which  contains  glue codes for all
rexxsyslib.library routines (rexx.lib).

===================== RexxHost.Library Functions =====================
======================================================================

CreateRexxHost - Create a RexxHost with supplied name

Usage:
RexxHost = CreateRexxHost(HostName)
  D0                         A0

This  function  tries  to  allocate a public messageport with a unique
name.   If  a  port  with the supplied name does already exist NULL is
returned.   The  name of the HostPort to be created is copied so there
is  no  need  to  keep  it  statically initialized in you application.
Note:   NEVER use this function if you only want to allocate a general
purpose  MsgPort.   Some  additional  type  checking  is  done in this
routine.   A  RexxHost  is  an  extended  MsgPort  structure with some
additional  data  which allows all library functions to test if a host
address  is valid.  You should rather see a RexxHost as a MsgPort.  Do
not  rely  on  the  existence  of  the  flags  following  the  MsgPort
structure.


DeleteRexxHost - Remove RexxHost

Usage:
NULL = DeleteRexxHost(RexxHost)
 D0              A0

A  supplied  RexxHost  is  removed  from the system, freeing allocated
signals  and  nodes.  A NULL-pointer is always returned so user can do
'Host  =  DeleteRexxHost(Host);'.  Never use this function to remove a
general   purpose   MsgPort  from  the  system  list,  in  which  case
DeleteRexxHost()  is  guaranteed  to  return immediately without doing
anything.


SendRexxCommand() - Send a command to the rexx server

Usage:
Success = SendRexxCommand(RexxHost,CommandString,FileExtension,HostName)
  D0                         A0          A1             A2        A3

This  function  causes  the  rexx  server  to  execute  a script file.
HostPort  must  point  to the host RexxHost, CommandString points to a
string   containing   the   name   of  the  command  to  be  executed.
FileExtension   and   HostName   are   optional   and   may  be  NULL.
FileExtension  defines  the  script  file name extension for this host
(for  standard rexx scripts this is ".rexx", for CygnusEd Professional
it  is  ".ced").   HostName  is  supplied to allow the host to address
different  sub-hosts, such as different windows a text editor may have
open.  This function returns FALSE (= 0) if the command cannot be sent
(rexx  may  not  be  running)  and  TRUE (= 1) if the message has been
posted.


FreeRexxCommand() - Free the contents of a RexxMsg

Usage:
FreeRexxCommand(RexxMessage)
                    A0

Having  successfully  called  SendRexxCommand()  the  rexx server will
return the RexxMsg with result flags set.  This kind of message cannot
be  replied (since it already has been replied by the rexx server) but
has  to  be  deallocated.   Be  sure  to examine the result code flags
before you remove the RexxMsg.


ReplyRexxCommand() - Returns a RexxMsg to the rexx server

Usage:
ReplyRexxCommand(RexxMessage,Primary,Secondary,Result)
                     A0         D0      D1       A1

Having received a command from the rexx server the host has to process
it.  After that the RexxMsg has to be replied so the rexx server knows
about  the  result.  Primary and Secondary are the values to be passed
in  the  result flags of the RexxMsg structure, Result is optional and
may  be  NULL.   It  usually  points to a string containing the result
(numeric or string) of the command having been executed.


GetRexxCommand() - Get the first argument from a RexxMsg

Usage:
String = GetRexxCommand(RexxMessage)
  D0                        A0

This  function  is  supported to save the calling program from dealing
with  pointer  offsets  (which  may  be  difficult  with some language
implementations).  It returns a pointer to the first argument entry in
the  supplied  RexxMsg  structure.   This  is  usually a command to be
executed by the host.  If NULL is returned then the RexxMsg is a reply
to a former SendRexxCommand() command.


GetRexxArg() - Get the first argument from a RexxMsg

Usage:
String = GetRexxArg(RexxMessage)
  D0                    A0

This  function  is  supported to save the calling program from dealing
with  pointer  offsets  (which  may  be  difficult  with some language
implementations).  It returns a pointer to the first argument entry in
the  supplied RexxMsg structure.  This function is almost identical to
GetRexxCommand(),  the  string  pointer is always returned, no RexxMsg
type consideration is done.


GetRexxResult1() - Get the first RexxMsg result code

Usage:
Result = GetRexxResult1(RexxMessage)
  D0                        A0

This  function  is  supported to save the calling program from dealing
with  pointer  offsets  (which  may  be  difficult  with some language
implementations).  It returns the value of the first result code entry
in the supplied RexxMsg structure.


GetRexxResult2() - Get the second RexxMsg result code

Usage:
Result = GetRexxResult2(RexxMessage)
  D0                        A0

This  function  is  supported to save the calling program from dealing
with  pointer  offsets  (which  may  be  difficult  with some language
implementations).   It  returns  the  value  of the second result code
entry in the supplied RexxMsg structure.


GetToken() - Get the next argument from a string

Usage:
Argument = GetToken(String,StartChar,AuxBuff,MaxLength)
   D0                 A0      A1       A2       D0

GetToken()  implements easy argument parsing.  ARexx posts commands as
NULL-terminated   strings   with   arguments   separated   by  spaces.
GetToken()  takes  a pointer to the command string (String), a pointer
to  a  counter  variable  (StartChar,  must be a long), a pointer to a
buffer the next argument will be copied to (AuxBuff) and the length of
the  buffer  the  next  argument  will  be copied to (MaxLength).  The
result  will be a pointer to AuxBuff if an argument was found, NULL if
the  end of the command string was reached.  You are to make sure that
the string pointed to by AuxBuff is long enough to hold the arguments.


GetStringValue() - Return the numeric value of a string

Usage:
Value = GetStringValue(String)
  D0                     A0

Just  like the 'C' language atoi() function GetStringValue() evaluates
the contents of a string.  Its value is returned as a long word.  This
function  helps  to  analyze  the contents of a RexxMsg result code or
command argument.


BuildValueString() - Turns a numeric value into a string

Usage:
String = BuildValueString(Value,String)
  D0                        D0    A0

This  function helps to build a string from a numeric value, just like
the  'C'  language  itoa() function.  The supplied string must be long
enough  to  hold  the digits built from Value.  A pointer to the built
string is returned.


RexxStrCmp() - Compare two strings ignoring case

Usage:
Match = RexxStrCmp(String1,String2)
  D0                 A0      A1

This  function  is  intended  to be a replacement for the 'C' function
strcmp().   Other than the builtin strcmp, RexxStrCmp ignores the case
of  both  strings  and even handles international characters correctly
(i.e.   RexxStrCmp("äöüß","ÄÖÜß")  == 0).  The value returned as Match
is  0  if both strings are considered equal, any other value indicates
that both strings are different.


GetRexxMsg() - Get a RexxMessage from a RexxHost

Usage:
RexxMsg = GetRexxMsg(RexxHost,WaitForIt)
   D0                   A0        D0

Use  this  function rather than calling GetMsg, since it does RexxHost
type  checking.   As  a  special option, it will wait for a message to
arrive  if  none  is  present  yet.   RexxHost  must  point to a valid
RexxHost  MsgPort structure, WaitForIt must be FALSE (= 0) if you want
this  function  to  return  immediately  if  there are no RexxMessages
pending, TRUE if otherwise.


SendRexxMsg() - Send a command to a Rexx host

Usage:
Result = SendRexxMsg(HostName,MsgList,SingleMsg,GetResult)
  D0                    A0      A1       A2        D0

Programs who wish to communicate directly with a Rexx host rather than
posting  lots  of scriptfiles call this function.  HostName must point
to  null  terminated  string  describing  the name of the Rexx host to
receive  the  command,  MsgList  points to an array of null terminated
strings,  SingleMsg points to a null terminated string.  Note:  Either
MsgList  or  SingleMsg  must  be NULL.  The MsgList is copied directly
into the 16 argument vectors of a RexxMsg.  SingleMsg will be put into
argument  vector  zero.  Set GetResult to TRUE if you want a result to
be  returned.   Note  that this function works synchronously and waits
until the reply to the message arrives.


GetRexxString() - Obtain and deallocate a result string

Usage:
GetRexxString(ResultString,DestString)
                   A0          A1

The  secondary  result code returned in a RexxMsg can be a string or a
number.  To save system memory the string has to be deallocated.  This
function  performs  two  actions for you:  it copies the result string
into a supplied buffer and deallocates the original string afterwards.
Note:   make sure the result you pass this function is really a string
and  not  a number or you will deallocate innocent memory.  ATTENTION!
There  is a very good chance that non-standard result strings (such as
returned  by CygnusEd Professional 2.xx) cannot be deallocated by this
function.   CEDPro2.xx does not use the standard RexxArg structure for
string  results, but stores the length of the string being returned in
the  first  longword  in front of the first character.  Sometimes this
string is not even null-terminated!


GetRexxClip() - Find a Rexx clip by name and return one argument

Usage:
ArgX = GetRexxClip(Name,WhichArg)
 D0                 A0     D0

The  rexx clip list is searched for a rexx resource node.  Returned is
either  Arg1  or  Arg2 depending on the value you pass as WhichArg:  a
value of 0 will return Arg1, 1 returns Arg2.

============================== Nuisance ==============================
======================================================================
The library could be shorter if the  Aztec 'C' linker  'LN'  generated
proper hunks:

1) DATA  and  BSS hunks are intermixed; as a result the BSS hunk turns
   out to have length zero which will still force DOS to allocate four
   extra bytes which are never used.

2) Additionally  the  DATA/BSS  hunk has to be zeroed 'manually' which
   requires some extra code in crt0.a68.

3) Even  if  you  don't  request a BSS hunk the linker still generates
   one.    The  -  empty  -  hunk  (including  superfluous  relocation
   information) occupies disk space it doesn't need.

       Is there any chance this 'kludging' will ever be fixed?

============================== Credits ===============================
======================================================================
rexxhost.library  was  built  from example source code written by Gary
Samad  &  Bill  Hawes (fancydemo.c), extensions & additional functions
were created by Olaf 'Olsen' Barthel.
   The  entire  contents  of  this library package may be used for any
purpose,  no  regard  whether commercial or non-commercial.  No credit
must  be  given  to  the  creator, nor must a registration fee be paid
(though I wouldn't mind if anybody did).

                     THIS IS TRULY PUBLIC DOMAIN!

=============================== Author ===============================
======================================================================

                               Olaf Barthel
                             Brabeckstrasse 35
                            D-3000 Hannover 71

                        Federal Republic of Germany

   I  may  also  answer questions asked via electronic mail.  My email
addresses are:

                   Z-Netz: O.BARTHEL@A-LINK-H
                   Usenet: o.barthel@a-link-h.comlink.de
                           olsen@sourcery.mxm.sub.org

============ Revision history (most recent change first) =============
======================================================================
37.1    Recompiled for use with Kickstart 2.0.

36.14   This  release  fixes  a  potential bug in the GetToken routine
        (Stefan Sticht discovered it).  Tokens may be separated by any
        blank  character  (such as tabs, spaces, newlines, etc.).  The
        Rexx   clip   list  can  be  scanned  using  a  new  function:
        GetRexxClip.   Due  to a bug to be found in the 'C' compiler I
        had  to  remove  the inline library calls and to turn off code
        optimization  in  the  LibMain  module.   Code size climbed by
        about 400 bytes.

35.13   Added    new    functions    (GetRexxMsg,    SendRexxMsg   and
        GetRexxString)   which  I  found  missing  for  the  last  few
        revisions.   I  also  rewrote parts of the library code to get
        rid of those nasty 'goto' statements.

34.12   The  library  can  be recompiled using 16 bit integers now.  I
        don't  know  if  anybody  profits  from  this feature but it's
        included  anyway.   By  the  way:   code  size went up to 2912
        bytes.

34.11   The library  went through  the third major rewrite, along with
        some  more cleanups (nobody told me that the NULL-function has
        to   be  supported)  assembly  language  string-routines  were
        introduced to reduce the amount of support-library code.  Code
        size dropped to 2840 bytes.

34.10   Some  more  cleanups  in  RexxStrCmp  and  other routines were
        really  necessary.   As  a  result,  code size went up to 2900
        bytes.

34.9    Added  more sanity checks in the Rexx Host creation/management
        procedure.  An extended MsgPort structure with additional type
        data  holds  the interface now.  Library code and data are now
        much  more  compact than in the previous releases (I spent two
        additional days debugging the code). Library  size  should  be
        2792 bytes now.

34.8    ANSIfication,   more   cleanups,   added  RexxStrCmp,  rewrote
        CreateRexxHost/DeleteRexxHost  to become shorter, made library
        use #pragma calls rather than  to  rely  on  the  rexxglue.asm
        output file. Code size went down to about 2764 bytes (original
        size: 3512 bytes).

34.7    Ported   to  Aztec  'C'  5.0,  the  strange  library  creation
        procedure  consumed lots of time (in which the author consumed
        lots of cups of coffee).

1.6     Initial creation using MkLib & elib.
