=========================================================================== ARexx 1.06 Copyright (c) 1988 by William S. Hawes =========================================================================== This is version 1.06 of ARexx, an implementation of the REXX language for the Amiga. ARexx can be used both as a general-purpose interactive programming tool and as the macro language for any applications program that provides the required command interface. ARexx is especially powerful for string-processing applications, and includes a source-level debugger to help simplify program development. ARexx is primarily a CLI-oriented programming tool and assumes that you'll use your favorite text editor to create the REXX program files. However, several icon files are available for WorkBench users. The "rexxmast" icon launches the resident process, a special server task that must be active before ARexx programs can be run. After running rexxmast, ARexx programs can be run from the CLI (using the "rx" command) or from within a program that interfaces to ARexx. The "rxc" icon closes the resident process. Refer to the "Update.doc" file for the latest information on updates to the ARexx software package. -- Installation -- ARexx can be installed on one or more of your system disks by simply copying the :c and :libs directories of the distribution disk to the C: and LIBS: directories, respectively. Alternatively, the program "RxInstall" can be used for the installation. Activate RxInstall from its icon or from the CLI; it will then read the required files and will prompt you to insert the destination system disk. RxInstall assumes that the target disk has been formatted as a system disk and that the :c and :libs directories exist. It will overwrite any pre-existing files with the same names as those in the :c and :libs directories, so make sure there are no naming conflicts before you run it. You can activate ARexx before you actually install it by double-clicking the "LoadLib" icon and then the "RexxMast" icon. Alternatively, you can run the startup script file called "Start-ARexx" from a CLI. -- Running ARexx Programs -- After you've installed the libraries and executable files, start the resident process by typing "rexxmast" (or double-clicking on the rexxmast icon). You can then run programs using the "rx" command at a CLI prompt, as in 1> rx :rexx/test Short programs can be entered directly at the command line by enclosing the program in double-quotes. For example, the following program will display the messages associated with ARexx error codes 1-5: 1> rx "do err=1 to 5;say err errortext(err);end" You can declare a system-wide directory for frequently-used ARexx programs by assigning REXX: to the appropriate directory. For example, 1> assign rexx: df0:rexx defines the :rexx directory of DF0: as the REXX: device. When you run an ARexx program, the language interpreter first searches your current directory and then checks the REXX: device for the specified file. If you're operating from a command shell (like WShell) that automatically recognizes the presence of ARexx, the "rx" command is no longer required; simply use the name of the REXX program as the command. -- ConMan -- This disk also includes release 1.1 of the ConMan console handler, the author's popular shareware program first released in April of 1987. ConMan is not required to run ARexx, but it makes the CLI much more convenient (and fun!) to use. It provides line-editing and command history functions, and allows you to open console windows with any of the standard Intuition attributes. Refer to the ConMan directory for more information. If you've never tried ConMan but would like to give it a quick test drive, double-click on the ConMan drawer, and then double-click first the "LoadLib" icon and then the "ConMan" icon. Now open a new CLI in your usual manner. You should find that the newly-opened CLI has line editing (using the left and right arrow keys) and command history (with the up/down arrows). -- Directories -- The following summarizes the general contents of the directories on the distribution disk: (root) -- Executable files, icons, and data files. "RxInstall" is a program to install the required ARexx files on a single-disk system. c -- The ARexx utility commands. "REXXMAST" launches the resident process, and "RX rexxfile [args ...]" executes an ARexx program. libs -- The (shared) libraries used by ARexx. rexx -- A potpourri of ARexx example programs. "Builtin.rexx" shows sample calls to all of the currently-implemented Built-In functions. tools -- Programs and executables for software developers. Not required if you just want to run ARexx programs. Includes an example function library ("RxExample") and a host command interface ("hosttest"). Also included are Modula-2 interface routines for BenchMark Modula-2, and the RexxMathLib and RexxARPLib external function libraries. include -- The header and include files needed to interface applications programs to ARexx. Binding ("glue") routines for calling the ARexx Systems Library are contained in the file "rexxglue.asm". ConMan -- Version 1.1 of the ConMan console handler replacement. Highly recommended for CLI users. Examples -- Example programs contributed by ARexx users. -- Bugs or Other Problems? -- The ARexx software has been extensively tested and should be very reliable. However, if you encounter a bug or other problem with the software, please report it promptly so that it can be corrected! Bug reports, questions, or other correspondence should be sent to: William S. Hawes P.O. Box 308 Maynard, MA 01754 (617) 568-8695 -- ARexx-Compatible Products -- There are a growing number of commercial products that support the ARexx command interface. At the present time (April, 1988) this list includes: AmigaTeX, an implementation of the TeX typesetting language (see the ARexx documentation for an example). Available from: Radical Eye Software P.O. Box 2081 Stanford, CA 94305 (415) 326-5312 TxEd-Plus, a text editor fully programmable using REXX-language macros. Available from: Microsmiths P.O. Box 561 Cambridge, MA 02140 (617) 354-1224 C.A.P.E.68K, an integrated assembler-editor whose editor interfaces to ARexx. Available from: Inovatronics 11311 Stemmons Freeway, Suite 7 Dallas, TX 75229 (214) 2411-9515 WShell, an enhanced but CLI-compatible command shell that provides aliases, resident commands, piping, and transparent support for REXX-language macros. Available from: William S. Hawes P.O. Box 308 Maynard, MA 01754 (617) 568-8695 Many other developers are working on interfacing their products with ARexx; write or call for information on currently-available products. -- Software Developers -- If you are working on an Amiga software product that could use the services of a powerful macro language, you may want to build an interface to ARexx. ARexx was designed as the macro-processor "engine" for a multitasking environment, and can turn your product into a fully programmable applications program. Any two programs that can talk to ARexx can thereby talk to each other, so by interfacing to ARexx you open the possibilities for end users to include your software in their own integrated applications. Interfacing to ARexx is remarkably easy and often requires only 1-2K of additional code in your software. The interface routines can be isolated in a side module for ease of maintenance, and with a properly designed interface your software will in no way depend on the presence of ARexx; it will simply use it if the ARexx server is active. The ARexx distribution disk contains the header and include files that you will need to implement the interface, and has some brief program examples to illustrate how the interface operates. Write for further information on interfacing to ARexx and on software distribution options. Update Notes on ARexx V1.06 Release 1.06 of ARexx incorporates a number of changes. All bugs reported to date have been corrected, and several new functions have been added to the Built-In function library. -- HighLights -- 1. Support for extended ASCII character set 2. Improved "string file" command parsing 3. New Built-In functions, including DATE() and SOURCELINE() 4. Definition files for BenchMark Modula-2 (see :tools/Modula-2) 5. Two new external function libraries: rexxmathlib and rexxarplib -- General -- An important change has been made to support the extended ASCII character set in ARexx programs. Previously the language interpreter had demanded that ARexx programs consist of just ASCII characters. This made it inconvenient (although possible!) to enter characters like "æ" or "å". The extended characters are now recognized as ordinary printing characters and will be correctly mapped from lowercase to uppercase. They are not considered as REXX symbol characters, though. The ARexx interface command parser has been generalized to recognize double-delimiter sequences within a (quoted) string file. The quoting convention that allows you to enter a REXX program as a string is very convenient for short programs, but it was easy to run out of quoting levels in the program. Note that single- and double-quotes WITHIN a REXX program are exactly equivalent, but that the external environment may make a distinction. For example, AmigaDOS uses only the double-quote as its quoting character, so string files entered from a CLI must begin with a double-quote, at least if you wish to include any semicolons. Example: 1> rx "say ""I can do multiple quotes now!""" The action of the RESULTS keyword of the OPTIONS instruction has been modified slightly: it now TOGGLES the result request, rather than setting it unconditionally. This makes it more convenient to set the RESULTS attribute for a single command without having to reset the FAILAT and PROMPT options. The PARSE SOURCE option now returns the full path name of the ARexx program file. Formerly only a relative name was given, which was not sufficient to locate the program's source file. A new command utility called "WaitForPort" is included in the :c directory. It waits for the specified port to appear, for a maximum of ten seconds. This is the preferred way to pause while a new ARexx host (or RexxMast) is started up. Note that the port name is case-sensitive. Example: waitforport REXX A patch program called PatchWB is included in the :c directory. It fixes a bug in Workbench that can cause problems when trying to run commands from programs started from Workbench. It works by clearing the pr_ConsoleTask field of Workbench's process block so that other programs won't inherit an invalid pointer. PatchWB should be included in your startup-sequence right after the LoadWB command. Example: LoadWB ; start Workbench PatchWB ; clear pointer -- Bug Fixes -- The // (integer division) operator did not work correctly in some cases, but should now be fully functional. The ~== operator now works correctly. Signed exponents like '1.23E-4' are now converted properly, and embedded signs like '123-456' are reported as conversion errors. ARexx now works with the V1.3 IEEE library to support the 68881 math coprocessor chip. Note however that the new IEEE library will cause a software error if a calculation overflows (result > 10**308); this has been reported as a problem to Commodore. There also seem to be some round-off related problems that introduce errors in calculations that should be (and were under V1.2) exact. Until these problems are fixed, you may want to continue using the 1.2 version of the math library. The spurious "Unexpected ELSE" error that occurred with certain control constructs has been fixed. The PARSE instruction has been changed to correctly handle the case of a pattern match at the beginning of the parse string. For example, PARSE VALUE ':file' WITH device ':' name will assign the null string to device and the value 'file' to name. The version string reported by PARSE VERSION now correctly indicates the video mode (NTSC or PAL) and vertical blanking frequency. OTHERWISE instructions can now be followed by a list of instructions without including a DO ... END construct. The TRIM() function has been fixed. It had a strange bug that made it work on my chosen test case, but in few other situations. The SYMBOL() and VALUE() Built-In functions now work correctly. The ARexx command parser now correctly processes "string files" declared with the RXFB_STRING bit. -- New Built-In Functions -- A few of the standard REXX functions were omitted in the initial release of ARexx. Of these, DATE() was missed the most, and a number of users wrote in requesting it. Mark Jones of Westwood, MA even went so far as to donate some 68000 assembly code to convert the AmigaDOS system date into the calendar year and month. After this groundswell of support for DATE(), I'm happy to report that the function is now fully implemented. DATE() Usage: DATE([option]) Returns the current date in the specified format. The default ('Normal') option returns the date in the form DD MMM YYYY, as in 20 Apr 1988. The options recognized are: Basedate -- returns the number of days since January 1, 0001 Century -- returns the number of days since January 1 of the century Days -- returns the number of days since January 1 of the current year European -- returns the date in the form DD/MM/YY Julian -- returns the date in the form YYDDD Month -- returns the current month (in mixed case) Normal -- returns the date in the form DD MMM YYYY Ordered -- returns the date in the form YY/MM/DD Sorted -- returns the date in the form YYYYMMDD USA -- returns the date in the form MM/DD/YY Weekday -- returns the days of the week (in mixed case) These options can be shortened to just the first character. Examples: say date() ==> 20 Apr 1988 say date('M') ==> April say date(s) ==> 19880420 DIGITS() Usage: DIGITS() Returns the current numeric digits setting. Example: numeric digits 6 say digits() ==> 6 FORM() Usage: FORM() Returns the current numeric form setting. Example: numeric form SCIENTIFIC say form() ==> SCIENTIFIC FUZZ() Usage: FUZZ() Returns the current numeric fuzz setting. Example: numeric fuzz 3 say fuzz() ==> 3 LINES() Usage: LINES(file) Returns the number of lines queued or typed ahead at the logical file, which must refer to an interactive stream. The stream must be managed by the ConMan console handler in order for the line count to be available; it is returned as the secondary result of a WaitForChar() call. Example: push 'a line' push 'another one' say lines(stdin) ==> 2 OFFSET() Usage: OFFSET(address,displacement) Computes a new address as the signed offset from a base address. The address argument must be a 4-byte string, and the displacement argument is a decimal integer. This function provides a convenient way to compute the address of a field in a data structure without requiring calls to C2D() and D2C(). Example: say c2x(offset('0000 0000'x,4)) ==> 00000676 PRAGMA() Usage: PRAGMA(option,value) A couple of changes were made to the existing PRAGMA() function. A new option keyword 'Id' will return the task ID (the address of the task block) as an 8-byte hex string. The task ID is a unique identifier of the particular ARexx invocation and may be used to create a unique name for it. The PRAGMA() 'Directory' option has been modified so that it now returns the full path name of the current directory; this allows the directory to be changed and then later restored. Examples: say pragma('D','df0:c') ==> ARexx1.06: say pragma('D','df1:c') ==> WorkBench:c say pragma('Id') ==> 00221ABC SOURCELINE() Usage: SOURCELINE([line]) Returns the text for the specified line of the currently executing ARexx program. If the line argument is omitted, the function returns the total number of lines in the file. This function is often used to embed "help" information in a program. Examples: /* A simple test program */ say sourceline() ==> 3 say sourceline(1) ==> /* A test program */ TRUNC() Usage: TRUNC(number,[places]) Returns the integer part of the number argument followed by the specified number of decimal places. The default number of decimal places is 0, and the number is padded with zeroes as necessary. Examples: say trunc(123.456) ==> 123 say trunc(123.456,4) ==> 123.4560 -- Support Library Functions -- One new function, DELAY(), has been added, and some new options have been implemented for several others of the support library functions. DELAY() Usage: DELAY(ticks) The DELAY() function waits for the specified number of ticks (1/50 second) and then returns. This function should be used whenever you need to suspend the execution of an ARexx program for some amount of time. While the program is waiting, the computer is free to execute other tasks. Example: call delay 100 /* two seconds */ SHOWDIR() Usage: SHOWDIR(directory,['All' | 'File' | 'Dir'],[separator]) The SHOWDIR() function now accepts a separator character as the third argument. Any character, including a null, can be used as a separator, so this provides a convenient way to separate filenames with a character that can't be used in the filename. Examples: say showdir('df1:c') ==> ts tcc rxc tco hi rxset rx rxlib te say showdir('df1:c',,';') ==> ts;tcc;rxc;tco;hi;rxset;rx;rxlib;te SHOWLIST() Usage: SHOWLIST(option,[name],[separator]) The SHOWLIST() function now accepts a separator character as the third argument. The separator can be any character, including a null, so it provides a convenient way to separate the list node names. The option list has been expanded in several ways. The EXEC MemList, IntrList, ResourceList, and SemaphoreList are now available, and the TaskReady list is now indicated by the 'T' option. In addition, the AmigaDOS device list can be examined by specifying 'Assign' (directories), 'Handlers' (devices), or 'Volumes'. The option can also be given as the (4-byte) absolute address of a list header; the function performs several tests to make sure that it really is a header. Examples: say showlist('Handlers') ==> DF0 DF1 CON RAW CNC say showlist('M',,';') ==> expansion ram;Chip Memory say showlist('A','FONTS') ==> 1 STATEF() Usage: STATEF(filename) The status reported by the STATEF() function now includes the timestamp associated with the file. The status string for a file formatted as FILE bytes blocks protection-flags days minutes ticks comment The days field is the number of days since January 1, 1978, the minutes field is the number of minutes since midnight, and the ticks field is the number of tick intervals (1/50 of a second) in the minute. The protection flags have been extended to include the Archive, Pure, Script, and Hidden attributes defined in the upcoming AmigaDOS V1.3 operating system release. The protection attributes are always reported in the order HSPARWED with a dash "-" if the attribute isn't present. Examples: say statef('c:') ==> DIR 0 0 ----RWED 3456 1234 12 say statef(':c/rxc') ==> FILE 408 1 --P-RWED 3620 1134 1827 -- Documentation Corrections -- An unfortunate number of errors remained in the ARexx documentation, in spite of repeated proofreadings and editing. These will be corrected in a future revision of the ARexx Users Manual. A few of the more important errata are mentioned here. PARSE EXTERNAL The documentation for this PARSE option is incorrect. PARSE EXTERNAL will read a line from the STDERR stream, rather than from STDIN, so as not to disturb any PUSHed or QUEUEd data. This is in the spirit of the standard EXTERNAL option. If STDERR is not defined, PARSE EXTERNAL returns the null string. Turning Tracing OFF The list on page 71 of the manual should include the TRACE OFF option. This is mentoned elsewhere in the manual, but was inadvertently omitted from the list of TRACE options. FREESPACE() Built-In Function Calling FREESPACE() with no arguments will return the amount of memory available in the interpreter's internal pool. RXLIB Command Utility The RXLIB command was omitted from the documention. It "mounts" a function library so that it can be called from ARexx, and can also be used to list the currently-defined functions. The command syntax is rxlib library-name priority offset version The priority argument gives the search priority and must be in the range -100 to 100 inclusive. The offset argument is the actual integer offset to the library's entry point and should be documented with each library. The version is the required library version and can usaully be omitted, as the default is to load any version. N.B. Do not get the offset value wrong! Calling a library with a bogus entry point will crash the machine. Anyone developing an external function library should carefully document the offset to the query (look-up) entry. Examples: rxlib rexxsupport.library 0 -30 0 rxlib rexxmathlib.library 5 -30 0 ARexx System Library Functions The function CVs2i is NOT available in the library; it was withdrawn at a late stage, but the document was not updated to reflect this. The converse situation occurs with the function LengthArgstring(); it IS available in the library and is used in a couple of the program examples. This function is the recommended way to extract the length of an argument string. The calling sequence is length = LengthArgstring(argptr) D0 A0 The CVi2arg function does not accept the digits argument in D1 that the documentation shows. Integers are converted at the maximum 12 digits. -- New External Function Libraries -- Willy Langeveld, a physicist at the Stanford Linear Accelerator, has written a couple of external function libraries for use with ARexx. The library rexxmathlib.library contains about two dozen math functions, including sqrt() and many transcendental functions. The library file and documentation (including source code) are in the :tools/rexxmathlib directory. Two versions are available: one that uses the IEEE library, and another to use the Microbotics Starboard II 68881 math coprocessor. The other library, rexxarplib.library, can be used to call the well-known ARP file requestor from within a REXX program. This makes a very handy tool for requesting a file name from the user while giving them a chance to review the available files. This library is in the :tools/RexxARPLib directory. The rexxmathlib.library and rexxarplib.library files should be copied to your LIBS: directory, and each function library must be "mounted" to make it known to the language interpreter. This can be done using the Built-In function ADDLIB() or the command utility rxlib. In the latter case, issue the command (for example) rxlib rexxmathlib.library 0 -30 0 to mount the math library at priority 0. Note that the offset parameter -30 MUST be given correctly; it is the actual function offset that will be called by the interperter. If you specify the wrong value, the machine will crash when you try to call a library function. The last 0 in the rxlib command is the library version, and 0 indicates that any version will do. The library files should be copied to your systems LIBS: -- Modula-2 Support -- Developers writing software in Modula-2 can now access the ARexx library. Thanks go out to Leon Frenkel of Avant-Garde Software, developer of the BenchMark Modula-2 compiler, who created the definition files and glue routines needed to call the ARexx systems library from Modula-2 programs. You'll find these files in the :tools/Modula-2 directory of the ARexx distribution disk. -- More Example Programs -- Some ARexx users have started sending in example programs, so I've created a new directory called "Examples" on the distribution disk. You'll find programs of every description in here, and most are designed to solve real-world problems rather than as contrived examples. Programs specific to one host (e.g. TxEd-Plus) will be found in the appropriate subdirectory. Want to share your favorite REXX programs? Send them in (with a suitable author credit commented in the program) and they may find their way onto a future distribution disk. -- Bill Hawes (May 3, 1988) Documentation for rexxserdev.library copyright © 1988 by Joseph M. Stivaletta All rights reserved. -------------------------------------------------------------------------- This is the beta version of my serial device function library for ARexx. Most of the functions have been implemented. I have not yet incorporated xon/xoff flow control. I hope to have these in the next version. This library uses ARP functions. Therefore, you must have arp.library in your LIBS: directory. You must also place my library into your LIBS: directory also. To use the Arexx serial device library, you must add it to the global library list using the either the addlib() function or the rxlib() command The current version number of this library is 1 and the query function offset is -30. examples follow: addlib( 'rexxserdev.library', 0, -30, 1 ) rxlib rexxserdev.library 0 -30 1 The rexxserdev.library was written to provide an easy to use interface between ARexx programs and the Amiga's internal serial device. The serial device is opened as shared so take care when accessing the serial device from more than one application. All I/O requests to the serial device are synchronous not asynchronous. Therefore, a call to a function will not return to the application until that function is completed. Due to the synchronous nature of the library functions the SerStart() and SerStop() functions may not work as designed for write calls. The actual effect of these calls has yet to be determined. At the current time I have not implemented SerStart(), SerStop() and SerGetParms(). ========================================================================== Using the functions SerOpen() Usage: boolean = SerOpen() Opens the serial device and allocates the I/O requests and reply ports. Example: say SerOpen() ==> 1 SerClose() Usage: boolean = SerClose() Closes the serial device and deallocates the I/O requests and reply ports. Example: say SerClose() ==> 1 SerClear() Usage: boolean = SerClear() Clears the internal read buffer. Example: say SerClear() ==> 1 SerFlush() Usage: boolean = SerFlush({'R' | 'W'}) Aborts all queued I/O requests in either the read or write request queue. Example: say SerFlush( 'R' ) ==> 1 SerRead() Usage: charsRcvd = SerRead(buffer,length) Read a number of characters from the serial port. The number of characters read is specified by length. The buffer is an internal read buffer supplied by the calling ARexx program. This buffer is for use by the rexxserdev.library and not by the ARexx application. Example: block = allocmem( 20 ) addr = c2d( block ) say SerRead( addr, 20 ) ==> A string of 20 chara SerReset() Usage: boolean = SerReset() Reinitializes the serial device to it's default state. Example: say SerReset() ==> 1 SerStart() Usage: boolean = SerStart({'R' | 'W'}) Restarts reading or writing stopped by a previous SerStop() function. Not yet implemented. Examples: say SerStart( 'W' ) ==> 1 SerStop() Usage: boolean = SerStop({'R' | 'W'}) Stops the currently executing read or write command. Not yet implemented. Example: say SerStop( 'R' ) ==> 1 SerWrite() Usage: boolean = SerWrite(buffer,length) Sends the characters in the buffer to the serial port. Example: text = 'send stuff out port' say SerWrite( text, length( text ) ) ==> 1 SerBreak() Usage: boolean = SerBreak() Sends a break signal. Examples: say SerBreak() ==> 1 SerQuery() Usage: status = SerQuery() Returns status of the serial device. The first substring indicates the validity of the rest of the string. 0 indicates that an error was returned from the query command and no additional information is contained within the status string. 1 indicates that the call was successful and the string contains two more substrings. The second substring is the number in decimal ASCII of the number of characters currently in the internal read buffer. The third substring is the status word in decimal ASCII it is defined as follows: Bit no. Meaning of Bit 0-2 Reserved 3 DSR - Data Set Ready (bit = 0) 4 CTS - Clear To Send (bit = 0) 5 DCD - Data Carrier Detect (bit = 0) 6 RTS - Ready To Send (bit = 0) 7 DTR - Data Terminal Ready (bit = 0) 8 Read buffer overflow (bit = 1) 9 Break signal sent (bit = 1) 10 Break signal received (bit = 1) 11 Transmit XOFF (bit = 1) 12 Received XOFF (bit = 1) 13-15 Reserved Examples: say SerQuery() ==> 1 23 0 | | +--> Status bits | +-----> Number of characters received +-------> Validity of status information SerSetParms() Usage: boolean = SerSetParms(baud,databits,paritybits,stopbits,[flowCtl],[brkTime]) Sets the serial device parameters defined below. The optional flowCtl and brkTime parameters are not yet implemented. I have not yet incorporated SERF_RAD_BOOGIE so take care when using very high baud rates. baud = allowed range is from 110 to 29,200 databits = allowed range from 1 to 8 paritybits = {'N' | 'E' | 'O' | 'M' | 'S'} 'N' = No parity 'E' = Even parity 'O' = Odd parity 'M' = Mark parity 'S' = Space parity stopbits = {'1' | '2'} flowCtl = {'0' | '1'} '0' = Disable Xon/Xoff flow control '1' = Enable Xon/Xoff flow control the default is disabled Xon/Xoff flow control brkTime = duration of break signal in microseconds; the default value is 250,000 microseconds. Examples: say SerSetParms( 9600, 7, e, 1 ) ==> 1 SerGetParms() Usage: SerGetParms() This function returns the current serial device parameters. This function has not been implemented yet. Examples: say SerGetParms() ==> 1 9600 7 e 1 2500000 0 ========================================================================== User rights This is a beta version of my library and I do not guarantee that it is free from bugs. It has been tested but not rigorously. I am making it available now so that people can begin using it. I will try to keep future versions downwardly compatible but make no promises that it will not change slightly based on user feedback. These programs are freely distributable in the public domain as long as this document is included. I retain the rights to their use. This means that they cannot be sold for profit by anyone without my written permission. ========================================================================== Disclaimer BS If this software, blows up your machine, melts you hard drive, causes loss of hair, mental anguish, mental disorders, or marital difficuties ending in divorce, I will not be held liable. I make no warranties, either expressed or implied, with respect to the programs described herein, their quality, performance, or fitness for any particular purpose. These programs are distributed "AS IS." The entire risk as to their quality and performance is with the user. I promise only to fix the bugs and to improve and enhance the code as I deem able in my spare time. ========================================================================== Problem reporting If you find any errors or have any problems, your flames can reach me at the following locations: Amiga Colony BBS (617-641-1629): Name: Joe Stivaletta IDCMP BBS (617-769-3172): Name: Joe Stivaletta CompuServe: PIN: 72155,516 People Link: ID: Blackhawk Delphi: ID: Blackhawk Bix: ID: jstivaletta Joseph M. Stivaletta P.O. Box 125 Bedford, MA 01730 14 June 1988