[comp.sources.amiga] v02i007: suplib-docs - documentation for Matt's support library

page@swan.ulowell.edu (Bob Page) (10/22/88)

Submitted-by: dillon@cory.berkeley.edu (Matt Dillon)
Posting-number: Volume 2, Issue 7
Archive-name: util/suplib.docs

[Matt sent 2 DISKS full of stuff ... my first week on the job! :-) ..Bob]

# This is a shell archive.  Remove anything before this line
# then unpack it by saving it in a file and typing "sh file"
# (Files unpacked will be owned by you and have default permissions).
# This archive contains the following files:
#	./dio.doc
#	./qint.doc
#	./summary.doc
#	./suplib.doc
#
if `test ! -s ./dio.doc`
then
echo "writing ./dio.doc"
cat > ./dio.doc << '\Rogue\Monster\'

				    DIO

    EXEC device driver IO support routines... makes everything easy.

    dfd = dio_open(name, unit, flags, req/NULL)

      open an IO device.  Note: in some cases you might have to provide a
      request structure with some fields initialized (example, the console
      device requires certain fields to be initialized).  For instance, if
      openning the SERIAL.DEVICE, you would want to give an IOExtSer
      structure which is completely blank execept for the io_SerFlags
      field.

      The request structure's message and reply ports need not be
      initialized.  The request structure is no longer needed after
      the dio_open().

      returns NULL = error, else DIO descriptor (a pointer) returned.


  dio_close(dfd)

      close an IO device.  Any pending asyncronous requests are
      AbortIO()'d and then Wait'ed on for completion.


  dio_closegrp(dfd)

      close EVERY DIO DESCRIPTOR ASSOCIATED WITH THE dio_open() call
      that was the parent for this descriptor.	That is, you can get
      a descriptor using dio_open(), dio_dup() it a couple of times,
      then use dio_closegrp() on any ONE of the resulting descriptors
      to close ALL of them.


  dio_cact(dfd,bool)

      If an error occurs (io_Error field), the io_Actual field is usually
      not modified by the device driver, and thus contains garbage.  To
      provide a cleaner interface, you can have the DIO_CTL() and
      DIO_CTL_TO() calls automatically pre-clear this field so if an
      io_Error does occur, the field is a definate 0 instead of garbage.

      In most cases you will want to do this.  An exception is the
      TIMER.DEVICE, which uses the io_Actual field for part of the timeout
      structure.

      This flags the particular dio descriptor to do the pre-clear, and any
      new descriptors obtained by DIO_DUP()ing this one will also have the
      pre-clear flag set.


  dio_dup(dfd)

      Returns a new channel descriptor referencing the same device. The new
      descriptor has it's own signal and IO request structure. For
      instance, if you openned the serial device, you might want to dup the
      descriptor so you can use one channel to pend an asyncronous read,
      and the other channel to write out to the device and do other things
      without disturbing the asyncronous read.


  sig = dio_signal(dfd)

      get the signal number (0..31) used for a DIO descriptor. This allows
      you to Wait() for asyncronous requests.  Note that if your Wait()
      returns, you should double check using dio_isdone()


  req = dio_ctl_to(dfd, command, buf, len, to)

      Same as DIO_CTL() below, but (A) is always syncronous, and (B) will
      attempt to AbortIO()+WaitIO() the request if the timeout occurs
      before the IO completes.

      the 'to' argument is in microseconds.

      If timeout occurs before request completes, and DIO aborts the
      request, some devices, such as the SERIAL.DEVICE do not have the
      io_Actual field set properly.  Always check the io_Error field for
      an abort before using io_Actual.


  req = dio_ctl(dfd, command, buf, len)

      DIO_CTL() is the basis for the entire library.  It works as follows:

      (1) If the channel isn't clear (there is an asyncronous IO request
	  still pending), DIO_CTL() waits for it to complete

      (2) If the command is 0, simply return a pointer to the io
	  request structure.

      (3) If the DIO_CACT() flag is TRUE, the io_Actual field of the
	  request is cleared.

      (4) Set the io_Data field to 'buf', and io_Length field to 'len'
	  If the command is positive, use DoIO().  If the command
	  negative, take it's absolute value and then do a SendIO().
	  (The command is placed in the io_Command field, of course).

      (5) return the IO request structure


  bool= dio_isdone(dfd)

      return 1 if current channel is clear (done processing), else 0. e.g.
      if you did, say, an asyncronous read, and dio_isdone() returns true,
      you can now use the data buffer returned and look at the io_Actual
      field.

      You need not do a dio_wait() after dio_isdone() returns 1.


  req = dio_wait(dfd)

      Wait on the current channel for the request to complete and then
      return the request structure. (nop if channel is clear)


  req = dio_abort(dfd)

      Abort the request on the current channel (nop if channel is
      clear).  Sends an AbortIO() if the channel is active and then
      WaitIO()'s the request.

    ------ MACROS ------

    dio_simple() and related macros return the !io_Error field. That
    is, 0=ERROR, 1=OK

    dio_actual() returns the io_Actual field instead of !io_Error.

    NOTE: the io_Actual field may not be set by the device if an
    error condition exists.  To make the io_ctl() and io_ctl_to()
    call automatically clear the io_Actual field before doing the
    io operation, use the DIO_CACT() call.  The reason this isn't
    done automatically by default is that some devices require
    parameters to be passed in the io_Actual field (like the
    timer.device).

    Remember, Asyncronous IO is done by sending -com instead of com.
    (that is, negative command).

      CALL			  Syncronous IO   Asyncronous IO

  dio_simple(dfd,com)             0=ERROR, 1=OK   undefined
  dio_actual(dfd,com)             io_Actual       undefined
  dio_reset(dfd)                  0=ERROR, 1=OK   n/a
  dio_update(dfd)                 0=ERROR, 1=OK   n/a
  dio_clear(dfd)                  0=ERROR, 1=OK   n/a
  dio_stop(dfd)                   0=ERROR, 1=OK   n/a
  dio_start(dfd)                  0=ERROR, 1=OK   n/a
  dio_flush(dfd)                  0=ERROR, 1=OK   n/a
  dio_getreq(dfd)                 returns a ptr to the IO
				  request structure

      NOTE: If you use the following, you probably want to have the device
      library automatically clear the io_Actual field before sending the
      request so you get 0 if an error occurs.	That is: dio_cact(dfd,1):

  dio_read(dfd,buf,len)           returns actual bytes read
  dio_write(dfd,buf,len)          returns actual bytes written

	The timeout argument for dio_readto() and dio_writeto()
	is in MICROSECONDS, up to 2^31uS.

  dio_readto(dfd,buf,len,to)      returns actual bytes read
  dio_writeto(dfd,buf,len,to)     returns actual bytes written

	The asyncronous dio_reada() and dio_writea() do not
	return anything.

  dio_reada(dfd,buf,len)          begin asyncronous read
  dio_writea(dfd,buf,len)         begin asyncronous write





\Rogue\Monster\
else
  echo "will not over write ./dio.doc"
fi
if [ `wc -c ./dio.doc | awk '{printf $1}'` -ne 6534 ]
then
echo `wc -c ./dio.doc | awk '{print "Got " $1 ", Expected " 6534}'`
fi
if `test ! -s ./qint.doc`
then
echo "writing ./qint.doc"
cat > ./qint.doc << '\Rogue\Monster\'

			   QINT DOCUMENTATION

	    Matthew Dillon

	    dillon@ucbvax.berkeley.edu	ARPA
	    ...!ihnp4!ucbvax!dillon	USENET

NOTE!!!!!   Lattice Users must replace the 'jsr _geta4' call with the
	    appropriate call to retrieve the address register for the
	    small data model before compiling!	You might have to make
	    other modifications as well (I don't know since I don't
	    have Lattice).


The Calls:
	char oldpri;	    range -128 to 127
	char newpri;
	char pri;
	long signum;	    0 .. 31

	void (*vector)();   function vector returning nothing
	void (*oldvec)();


    While active Q interrupt vectors exist, the tc_ExceptCode in the
    task structure will be modified.  The old tc_ExceptCode is used if
    an unknown exception occurs (one that is not a Q interrupt).

    oldpri = SetQPri(newpri)

	Set the task's current Q priority.  Any Q interrupts of lower or
	equal priority that occur will be queued until the priority is
	dropped sufficiently.

	The initial task priority is -128 (essentially allowing all Q
	interrupts -127 to 127 to occur).

    oldvec = SetQVector(signum, vector, arg, pri)

	If vector is non-null, enables the exception at the specified
	priority (-127 to 127).  specified vector is called in a C
	compatible way with one user argument (arg).  Specifying a
	priority of -128 does not make sense because this is the lowest
	allowed priority and the Q interrupt will thus never occur.

	If vector is null, the exception and Q interrupt is disabled.
	After the last Q interrupt is removed, tc_ExceptCode is restored
	to its original value.


BUGS:
	The only bug that I know of is a problem with EXEC.

	What is Good:	An exception will not occur while one is Forbid()n
	What is Bad:	If an exception comes in while Forbid()n, it will
			NOT be immediately entered when you Permit().

	Whoops.  The exception *will* occur when EXEC next checks its
	signals and exceptions, which occurs on the obvious EXEC library
	calls (SetExcept(), SetSignal(), etc...)  and perhaps Wait().

	In most cases you can ignore the problem.


GENERAL WORKINGS OF Q INTERRUPTS:

	If you know how EXEC signals and the 68000 interrupt structure
	works, then you know how Q interrupts work.  Simply replace
	"processor" with "task" and "0-7" with "-128 to 127" for task
	Q interrupt priorities (this is different from the Task's
	scheduler priority).

	Q interrupts work just like 68000 interrupts.  If the task is
	currently running at a Q interrupt priority N, only Q interrupts
	of HIGHER priority can occur.  Q interrupts of LOWER OR EQUAL
	priority are queued and will occur as soon as the priority is
	lowered.  Everything occurs in priority order, the highest priority
	pending interrupt is always the one running (or the task's main
	routine if it has the highest priority).

	Thus, while a Q interrupt handler is running at some specific
	priority, other Q interrupts at the same priority will wait
	until the first one finishes and then execute in a FIFO fashion.

THE INTERRUPT VECTOR ROUTINE:

	A specific Q interrupt vector is a C subroutine called with one
	longword argument (that specified when you SetQVector()'d it).
	This works fine with the small model.

	The handler runs with all normal EXEC processing enabled, and in
	the context of its task.  It can be viewed almost as a subroutine
	call from the task.  However, you must be careful about the
	reentrancy of certain functions.  STDIO, DOS, and many other
	library calls are not reentrant, and you must use SetQPri() to
	ensure such calls are not interrupted.	NOTE that you CAN mix
	certain calls.	I don't have much info on what combinations work,
	but certainly most library calls that do not depend on being
	called singularly from tasks will work (for example, GetMsg()).
	And, of course, if all your handler does is make some small
	calculations this can interrupt anything.

	If you cause an exception (the same exception) from within the
	handler, it will be remembered.  (That is, the signal is cleared
	before the handler is called), and occur after your handler
	returns.

USES FOR Q INTERRUPTS:

	Use #1:     To be able to execute menu options which do not effect
		    the 'current' operation.  E.G. if you are doing a
		    ray tracing you could make the intuition window's
		    signal bit a Q interrupt and handle Intuition messages
		    that way....   The main loop generating the ray
		    tracing would not have to continuously check for
		    Intuition messages.

	Use #2:     Lets say you are writing a terminal program and want
		    to display data comming in smoothly while sending a
		    file.  While this can be done easily with the
		    asynchronous ability of IO devices, it would be even
		    easier if you handled the receive with a Q interrupt...
		    that way, you could display received data (SendIO to
		    the console device) even if the file sender is in
		    the middle of a DOS call to read the next file block.

	Many more uses (I hope!).

			    -Matt


\Rogue\Monster\
else
  echo "will not over write ./qint.doc"
fi
if [ `wc -c ./qint.doc | awk '{printf $1}'` -ne 4986 ]
then
echo `wc -c ./qint.doc | awk '{print "Got " $1 ", Expected " 4986}'`
fi
if `test ! -s ./summary.doc`
then
echo "writing ./summary.doc"
cat > ./summary.doc << '\Rogue\Monster\'

SUMMARY.DOC	Summary of library functions


			-------- ASYNCHRONOUS FILE SUPPORT --------


    xfi =   xfopen(file, mode, bytes)       mode: r-read w-write w+-append
    err =   xfclose(xfi)
     n	=   xfread(xfi, buf, n)             0 on EOF/error
     n	=   xfgets(xfi, buf, max)           -1 on EOF/error else string length
    err =   xfwrite(xfi, buf, n)

	    bmov(src,dest,bytes)
	    bcmp(src,dest,bytes)
	    bset(src, bytes, c)
	    bzero(src, bytes)

	    checkbreak()
	    resetbreak()
	    disablebreak()      (not available as a run-time library call)
	    enablebreak()       (not available as a run-time library call)

	    openlibs(flags)
	    closelibs(flags)
	    closelibs(-1)       close all libraries openned w/ openlibs()

     bool = wildcmp(wildstr, namestr)

	    mountrequest(bool)

	    fhprintf(fh, ctrlstr, args...)

	    llink(list, en)         (OBSOLETE)
	    lunlink(en)             (OBSOLETE)

			    SYSTEM SUPPORT

     port = CreateUniquePort(name, priority)    create port w/unique name
	    DeleteUniquePort(port)              delete port w/unique name
	    PutSyncMsg(port, msg)               normal synchronous message
	    PutSyncMsgSimple(port, ptr, cmd)    simple synchronous message
   retcmd = WaitMsg(msg)                        wait for message to come back
	    CheckMsg(msg)                       check if message has come back
	    GetHead(list)
	    GetTail(list)
	    NextNode(node)

			      IO SUPPORT

      dfd = dio_open(name, unit, flags, req/NULL)
	    dio_close(dfd)
	    dio_closegrp(dfd)
	    dio_cact(dfd,bool)
	    dio_dup(dfd)
      sig = dio_signal(dfd)
      req = dio_ctl_to(dfd, command, buf, len, to)
      req = dio_ctl(dfd, command, buf, len)
      bool= dio_isdone(dfd)
      req = dio_wait(dfd)
      req = dio_abort(dfd)

	    also a large array of macros are available.  if command < 0, then
	    asyncronous execution is implied.  Macros:

					    SYCHRONOUS	    ASYNCHRONOUS

	    dio_simple(dfd,com)             0=ERROR, 1=OK   undefined
	    dio_actual(dfd,com)             io_Actual       undefined
	    dio_reset(dfd)                  0=ERROR, 1=OK   n/a
	    dio_update(dfd)                 0=ERROR, 1=OK   n/a
	    dio_clear(dfd)                  0=ERROR, 1=OK   n/a
	    dio_stop(dfd)                   0=ERROR, 1=OK   n/a
	    dio_start(dfd)                  0=ERROR, 1=OK   n/a
	    dio_flush(dfd)                  0=ERROR, 1=OK   n/a
	    dio_getreq(dfd)                 returns a ptr to the IO request structure
	    dio_read(dfd,buf,len)           returns actual bytes read
	    dio_write(dfd,buf,len)          returns actual bytes written

	    dio_readto(dfd,buf,len,to)      returns actual bytes read
	    dio_writeto(dfd,buf,len,to)     returns actual bytes written

	    dio_reada(dfd,buf,len)          begin asyncronous read
	    dio_writea(dfd,buf,len)         begin asyncronous write


\Rogue\Monster\
else
  echo "will not over write ./summary.doc"
fi
if [ `wc -c ./summary.doc | awk '{printf $1}'` -ne 2888 ]
then
echo `wc -c ./summary.doc | awk '{print "Got " $1 ", Expected " 2888}'`
fi
if `test ! -s ./suplib.doc`
then
echo "writing ./suplib.doc"
cat > ./suplib.doc << '\Rogue\Monster\'

SUPLIB.DOC	General C Support Library

			    COMPILATION

    Compile all modules using a precompiled symbol table of all the
    AMIGA include's (*/*.H) ... do *NOT* include standard aztec
    includes (stdio.h, etc...).  The Makefile for the precompiled symbol
    table is in the LOCAL directory.

    You must use the +L option (32 bit ints) for ALL COMPILATIONS, including
    the generation of the symbol table when compiling SUPLIB (SUP32.LIB).
    Also, use +B (no .begin reference), +CD (large code and data) model
    when compiling this source.


				    MODULES

    QINT:	These are exception based prioritized software interrupt
		routines.  see QINT.DOC

    ASYNCOP:	Asynchronous function execution.  Make asynchronous
		function calls (not incredibly fast).

    XFIO:	Asyncronous file IO.  Allows sequential asyncronous access
		to files for both reading (reads ahead asyncronously) and
		writing (writes asyncronously).  Usually employed by CPU
		bound programs not wishing to be slowed down even more by
		the disk.  Extremely useful for implementation of capture
		and serial protocols.

    DIO:	Device IO package.  This is a Generic interface for handling
		the Amiga's EXEC devices.  It makes your code smaller and
		much easier to read.  You no longer need to be a guru to
		use devices.

    BSTRING:	memory move/set/compare routines.  Operations are done in
		longwords when possible.

    SYS:	System enhancement calls

    MISC:	misc. routines (break checking, openning/closing libraries),
		date and time routines, setfiledate, etc...


    ---------------------------------------------------------------------

			       QINTS

    SEE QINT.DOC


			      ASYNCH OP

handle= NewAsyncOp()

	Create a new task for handling asynchronous function calls.

(void)  StartAsyncOp(handle, func, arg1, arg2, arg3)

	Queue up a function for the handle.  Multiple functions may
	be queueud.  NOTE:  The registers A4 and A5 will be initialized
	to what they were when NewAsyncOp() was called.

	The function must preserve D4-D7/A2-A3.  D0-D3/A0-A1/A4-A6 may
	be destroyed by the function.


bool  = CheckAsyncOp(handle, n)

	Return TRUE if a minimum of N async operations started with
	StartAsyncOp() have completed, FALSE otherwise.  The number
	of async operations in progress is the number started minus
	the number already waited for.

(void)= WaitAsyncOp(handle, n)

	Wait for N of the operations in progress to complete.  -1 can
	be specified to wait for ALL the operations in progress to
	complete.

	For example, if you queue up 3 commands, CheckAsyncOp(handle, 3)
	will check if all 3 have completed, and WaitAsyncOp(handle, 3)
	waits and removes their reply messages as well as adjusts the
	number of 'operations in progress' to 0.

	I.E, if you were to WaitAsyncOp(handle, 2) instead of 3, after
	it returns there will be 1 operation in progress left.	If you
	were to do another StartAsyncOp(), there would now by 2 in
	progress.

(void)  CloseAsyncOp(handle)

	Wait for all operations in progress to end (WaitAsyncOp(handle,-1)),
	then remove the task.

				 XFIO


    xfi =   xfopen(file, mode, bytes)
    err =   xfclose(xfi)
     n	=   xfread(xfi, buf, n)
     n	=   xfgets(xfi, buf, max)
    err =   xfwrite(xfi, buf, n)

		mode is "r", "w", or "w+".  No seeking is allowed as you can
		see.  If you openned for reading, you may NOT use xfwrite(),
		and if you openned for writing, you may NOT use xfread().

		r   read
		w   write-newfile
		w+  write-append

		The specified buffer size (bytes) is used to create two
		buffers of (bytes/2) bytes, double buffering either
		asyncronous read ahead, or asyncronous writes.

		'err' returns 1 if a write error occured.  err is returned
		by xfclose() (xfclose() waits for any asyncronous writes
		to complete and thus can return whether they failed or not).
		Once set, err stays set forever.

		XFREAD: 0 is returned on EOF or error
		XFGETS: the length of the string is returned.  0 is a valid
			length (a blank line).  -1 is returned on EOF or
			error.	The newline is removed and a string
			terminator (0) added.


				DIO

	 SEE DIO.DOC


			       BSTRING

(void)  bmov(src,dest,bytes)
bool  = bcmp(src,dest,bytes)
(void)  bset(src, bytes, c)
(void)  bzero(src, bytes)

	These functions do various memory operations.  bcmp() is does an
	unsigned comparison, of course.  bcmp() only checks for
	equivalence, returning TRUE (1) if the buffers are the same,
	FALSE (0) otherwise.  bcmp() uses longword compares when possible.

	bmov() does an ascending or decending copy as appropriate.
	bmov(), bzero(), and bset() use longword and MULTIPLE REGISTER
	operations when possible.

	These functions are the same as the BSet(), BZero(), BMov(), and
	BCmp() in my run-time library DRES.LIBRARY.

bool =	checkbreak()

	Check whether the process has received a ^C or ^D signal.  ^D
	is also checked here allowing a more reliable break-mechanism,
	as Aztec and Lattice stdio routines will clear ^C even when
	break is disabled.

(void)  resetbreak()
(void)  disablebreak()
(void)  enablebreak()

	resetbreak() clears both the ^C and ^D signals.  disablebreak()
	and enablebreak() modify the global variable Enable_Abort and
	thus stdio's automatic break detection/abort.


bool  = openlibs(flags)
bool  = closelibs(flags)

	See the flag definitions in XMISC.H.  openlibs() opens all
	specified libraries, returning 0 if one or more could not
	be openned.  closelibs() closes all specified libraries.
	openlibs() does not open a library that is already open (if you
	make the call more than once), and simply uses the already
	open descriptor.

	closelibs(-1) closes ALL libraries openned with openlibs(), but
	NOT libraries openned otherwise.

	Note that you cannot open or close DOS or EXEC.  This is because
	the C startup will do this for you, and also to prevent linker
	warning messages.

Window= GetConWindow()

	This functions retrieves the struct Window * from the console
	device associated with this process.  NULL is returned if the
	window could not be found (still, operation may not be dependable
	if the process's console is not a console device).

buf   = datetos(date, buf, ctl)
	DATESTAMP *date;
	char *buf;
	char *ctl;

	This function converts a DOS DateStamp structure into a string
	and places it in the specified buffer.	ctl specifies the format
	of the date by pieces (ctl can be NULL, indicating "D M Y h:m:s").

	If not NULL, ctl is a string containing combinations of the
	following characters.  Spacing must also be specified.	Any
	unrecognized characters are passed to the output buffer verbatim.

	    D	The day 	23
	    M	The month	Jul
	    Y	The year	1988
	    h	The hour	03
	    m	The minute	23
	    s	The seconds	04

	This function is equivalent to DateToS() in my run time library
	DRES.LIBRARY

(void)  llink(list, en)         (OBSOLETE)
(void)  lunlink(en)             (OBSOLETE)

	see XMISC.H .  Simple doubly-linked list routines.  XLIST is both
	the list base and an element.  The list base should be initialized
	to zero before use.

(void)  mountrequest(bool)

	enable or disable the DOS requester which comes up when you attempt
	to open a path not currently mounted.  Normal mode is TRUE (1),
	meaning that you get the requester.  This routine remembers the
	previous contents of pr_WindowPtr.  The call mountrequest(0) may
	be made multiple times and then mountrequest(1) will restore the
	original contents of pr_WindowPtr.

RemSemaphore()
FindSemaphore()     (SEE EXEC DOCUMENTATION FOR CALLING PARAMETERS)
AddSemaphore()

	These functions fix the broken bindings in older Lattice and
	Aztec libraries.

bool  = setfiledate(file, date)
	char *file;
	DATESTAMP *date;

	This function implements the new ACTION_SET_DATE packet and
	sets the timestamp of a file.  You cannot set the timestamp
	for the root of a filesystem with this call.

	This function is equivalent to the SetFileDate() function in
	DRES.LIBRARY.

bool =	wildcmp(wildstr, namestr)

	compare the wildcard string (containing '*'s and '?'s) with
	the file name (namestr) and return TRUE (1) if they compare,
	and FALSE (0) otherwise.

	This function is equivalent to the WildCmp() function in
	DRES.LIBRARY.

(void)  fhprintf(fh, ctrlstr, args...)

	uses the EXEC formatted printing call to format text and then
	writes it to an AMIGADOS file handle.


rval  = AutoAllocMiscResource(resno, value)

	resno: MR_SERIALPORT, SERIALBITS, PARALLELPORT, or PARALLELBITS
	value:	-1 to allocate, 0 to check.

	This functions allocates or checks the specified resource.  0
	(ZERO) is returned on SUCCESS (allocated or could allocate),

	NON-ZERO is returned if the resource is already allocated by
	somebody else.

(void)= AutoFreeMiscResource(resno)

	Free's a resource you allocated.  YOU MUST OWN THE RESOURCE!

	Neither of these functions require you to open the misc.resource
	resource.

font  = GetFont(name, ysize)

	This function searches both memory and the disk for the requested
	font, and automatically opens/closes the diskfont library if it is
	not already open.  It opens the font, incrementing the reference
	count.

(void)  InitDeemuNW(ary, nw)
	short *ary;
	NW *nw;

	ary points to the 'NW','  ' Deemu[] array entry.  The NewWindow
	structure is initialized according to the Deemu entry.	Currently,
	TopEdge, LeftEdge, Width, Height, DetailPen and BlockPen will
	be initialized... less if the Deemu entry contains less information.

char   *GetDEnv(name)
	char *name;

	Return a string to the enviroment variable name, returning NULL
	if it does not exist.

bool	SetDEnv(name, str)
	char *name, *str;

	Set the enviroment variable name to the string str.  Return C-TRUE
	(1) on success, or C-FALSE (0) on failure.



\Rogue\Monster\
else
  echo "will not over write ./suplib.doc"
fi
if [ `wc -c ./suplib.doc | awk '{printf $1}'` -ne 9714 ]
then
echo `wc -c ./suplib.doc | awk '{print "Got " $1 ", Expected " 9714}'`
fi
echo "Finished archive 1 of 1"
# if you want to concatenate archives, remove anything after this line
exit
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.