====================== RexxHost.Library v36.14 ======================= ====================================================================== 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. ========================= Supplied material ========================== ====================================================================== The RexxHostLib package contains the following files: ----------------------------------------------------- FancyDemo.............. Demonstration program FancyDemo.c............ Source code for demonstration program LibStartup.asm......... Library support code LibMain.c.............. Library support code PreInclude.c........... Source for precompiled header file RexxHostLib.c.......... Library support code rexxhostbase.h......... Library header file StringAsm.asm.......... Assembly language string routines rexxhostlat.lib........ Lattice 'C' linker library rexxhostnew.lib........ Aztec 'C' 5.0 linker library rexxhostold.lib........ Aztec 'C' 3.6 linker library rexxhost.library....... Amiga shared library MakeFile............... Library building-instructions rexxhost_lib.fd........ Library function definitions TestDemo.rexx.......... ARexx demonstration script RexxHost.doc........... This file Glue.LZH............... LhArc archive containing library glue routine source codes ============================= 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 'Olsen' Barthel, MXM Brabeckstrasse 35 D-3000 Hannover 71 Federal Republic of Germany Phone: (05 11) 52 23 38 ============ Revision history (most recent change first) ============= ====================================================================== 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.