page@ulowell.UUCP (Bob Page) (03/20/86)
# Here are the latest header files for IFF. Most of the files are # dated. I recently posted new IFF spec documents for ILBM, FTXT, # 8SVX and SMUS. Contact me by mail (don't post to the net) # if you didn't receive them and you want them. # # I will post the IFF source code in a few days. # # Bob Page, ulowell!page (preferred) or page@ulowell.csnet # ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory for the files. # # 2) Write a file, such as "file.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo x - compiler.h: cat >compiler.h <<\STUNKYFLUFF #ifndef COMPILER_H #define COMPILER_H /*** compiler.h *********************************************************/ /* Steve Shaw 1/29/86 */ /* Portability file to handle compiler idiosyncrasies. */ /* Version: Lattice 3.03 cross-compiler for the Amiga from the IBM PC. */ /* */ /* This software is in the public domain. */ /* */ /************************************************************************/ #ifndef EXEC_TYPES_H #include "exec/types.h" #endif /* NOTE -- NOTE -- NOTE -- NOTE -- NOTE * Some C compilers can handle Function Declarations with Argument Types * (FDwAT) like this: * extern LONG Seek(BPTR, LONG, LONG) * while others choke unless you just say * extern LONG Seek() * * Comment out the #define FDwAT if you have a compiler that chokes. */ /* Greenhills can't take it */ /* Aztec C can't take it */ #define FDwAT /* OK for Lattice */ #endif COMPILER_H STUNKYFLUFF set `sum compiler.h` if test 20345 != $1 then echo compiler.h: Checksum error. Is: $1, should be: 20345. fi # # echo x - gio.h: cat >gio.h <<\STUNKYFLUFF #ifndef GIO_H #define GIO_H /*----------------------------------------------------------------------*/ /* GIO.H defs for Generic I/O Speed Up Package. 1/23/86 */ /* See GIOCall.C for an example of usage. */ /* Read not speeded-up yet. Only one Write file buffered at a time. */ /* */ /* Note: The speed-up provided is ONLY significant for code such as IFF */ /* which does numerous small Writes and Seeks. */ /* */ /* WARNING: If gio reports an error to you and you care what specific */ /* Dos error was, you must call IoErr() BEFORE calling any other gio */ /* functions. */ /* */ /* By Jerry Morrison and Steve Shaw, Electronic Arts. */ /* This software is in the public domain. */ /* */ /* This version for the Commodore-Amiga computer. */ /* */ /*----------------------------------------------------------------------*/ /* Use this file interface in place of ALL Open,Close,Read,Write,Seek DOS * calls for an optional i/o speed-up via buffering. You must use ONLY * these G routines for a file that is being buffered; e.g., call GClose * to Close the file, etc. * It is harmless though not necessary to use G routines for a file that * is not being buffered; e.g., GClose and Close are equivalent in that * case. * This Version only buffers one file at a time, and only for writing. * If you call GWriteDeclare for a second file before the first file * is GClosed, the first file becomes unbuffered. This is harmless, no * data is lost, the first file is simply no longer speeded-up. */ /* Before compiling any modules that make G calls, or compiling gio.c, * you must set the GIO_ACTIVE flag below. * * To omit the speed-up code, * #define GIO_ACTIVE 0 * * To make the speed-up happen: * 1. #define GIO_ACTIVE 1 * 2. link gio.o into your progrm * 3. GWriteDeclare(file, buffer, size) * after GOpening the file and before doing * any writing. * 4. ONLY use GRead, GWrite, GSeek, GClose -- do not use the DOS i/o * routines directly. * 5. When done, do GClose. Or to stop buffering without closing the * file, do GWriteUndeclare(file). */ #define GIO_ACTIVE 0 #ifndef COMPILER_H #include "iff/compiler.h" #endif #ifndef LIBRARIES_DOS_H #include "libraries/dos.h" #endif #ifndef OFFSET_BEGINNING #define OFFSET_BEGINNING OFFSET_BEGINING #endif #if GIO_ACTIVE #ifdef FDwAT /* Compiler handles Function Declaration with Argument Types */ /* Present for completeness in the interface. * "openmode" is either MODE_OLDFILE to read/write an existing file, or * MODE_NEWFILE to write a new file. * RETURNs a "file" pointer to a system-supplied structure that describes * the open file. This pointer is passed in to the other routines below.*/ extern BPTR GOpen(char * /*filename*/, LONG /*openmode*/); /* NOTE: Flushes & Frees the write buffer. * Returns -1 on error from Write.*/ extern LONG GClose(BPTR /*file*/); /* Read not speeded-up yet. * GOpen the file, then do GReads to get successive chunks of data in * the file. Assumes the system can handle any number of bytes in each * call, regardless of any block-structure of the device being read from. * When done, GClose to free any system resources associated with an * open file.*/ extern LONG GRead(BPTR /*file*/, BYTE * /*buffer*/, LONG /*nBytes*/); /* Writes out any data in write buffer for file. * NOTE WHEN have Seeked into middle of buffer: * GWriteFlush causes current position to be the end of the data written. * -1 on error from Write.*/ extern LONG GWriteFlush(BPTR /*file*/); /* Sets up variables to describe a write buffer for the file.*/ /* If the buffer already has data in it from an outstanding GWriteDeclare, * then that buffer must first be flushed. * RETURN -1 on error from Write for that previous buffer flush. * See also "GWriteUndeclare".*/ extern LONG GWriteDeclare(BPTR /*file*/, BYTE * /*buffer*/, LONG /*nBytes*/); /* ANY PROGRAM WHICH USES "GWrite" MUST USE "GSeek" rather than "Seek" * TO SEEK ON A FILE BEING WRITTEN WITH "GWrite". * "Write" with Generic speed-up. * -1 on error from Write. else returns # bytes written to disk. * Call GOpen, then do successive GWrites with GSeeks if required, * then GClose when done. (IFF does require GSeek.)*/ extern LONG GWrite(BPTR /*file*/, BYTE * /*buffer*/, LONG /*nBytes*/); /* "Seek" with Generic speed-up, for a file being written with GWrite.*/ /* Returns what Seek returns, which appears to be the position BEFORE * seeking, though the documentation says it returns the NEW position. * In fact, the code now explicitly returns the OLD position when * seeking within the buffer. * Eventually, will support two independent files, one being read, the * other being written. Or could support even more. Designed so is safe * to call even for files which aren't being buffered.*/ extern LONG GSeek(BPTR /*file*/, LONG /*position*/, LONG /*mode*/); #else /*not FDwAT*/ extern BPTR GOpen(); extern LONG GClose(); extern LONG GRead(); extern LONG GWriteFlush(); extern LONG GWriteDeclare(); extern LONG GWrite(); extern LONG GSeek(); #endif FDwAT #else /* not GIO_ACTIVE */ #define GOpen(filename, openmode) Open(filename, openmode) #define GClose(file) Close(file) #define GRead(file, buffer, nBytes) Read(file, buffer, nBytes) #define GWriteFlush(file) (0) #define GWriteDeclare(file, buffer, nBytes) (0) #define GWrite(file, buffer, nBytes) Write(file, buffer, nBytes) #define GSeek(file, position, mode) Seek(file, position, mode) #endif GIO_ACTIVE /* Release the buffer for that file, flushing it to disk if it has any * contents. GWriteUndeclare(NULL) to release ALL buffers. * Currently, only one file can be buffered at a time anyway.*/ #define GWriteUndeclare(file) GWriteDeclare(file, NULL, 0) #endif STUNKYFLUFF set `sum gio.h` if test 22472 != $1 then echo gio.h: Checksum error. Is: $1, should be: 22472. fi # # echo x - iff.h: cat >iff.h <<\STUNKYFLUFF #ifndef IFF_H #define IFF_H /*----------------------------------------------------------------------*/ /* IFF.H defs for IFF-85 Interchange Format Files. 1/22/86 */ /* */ /* By Jerry Morrison and Steve Shaw, Electronic Arts. */ /* This software is in the public domain. */ /*----------------------------------------------------------------------*/ #ifndef COMPILER_H #include "iff/compiler.h" #endif #ifndef LIBRARIES_DOS_H #include "libraries/dos.h" #endif #ifndef OFFSET_BEGINNING #define OFFSET_BEGINNING OFFSET_BEGINING #endif typedef LONG IFFP; /* Status code result from an IFF procedure */ /* LONG, because must be type compatable with ID for GetChunkHdr.*/ /* Note that the error codes below are not legal IDs.*/ #define IFF_OKAY 0L /* Keep going...*/ #define END_MARK -1L /* As if there was a chunk at end of group.*/ #define IFF_DONE -2L /* clientProc returns this when it has READ enough. * It means return thru all levels. File is Okay.*/ #define DOS_ERROR -3L #define NOT_IFF -4L /* not an IFF file.*/ #define NO_FILE -5L /* Tried to open file, DOS didn't find it.*/ #define CLIENT_ERROR -6L /* Client made invalid request, for instance, write * a negative size chunk.*/ #define BAD_FORM -7L /* A client read proc complains about FORM semantics; * e.g. valid IFF, but missing a required chunk.*/ #define SHORT_CHUNK -8L /* Client asked to IFFReadBytes more bytes than left * in the chunk. Could be client bug or bad form.*/ #define BAD_IFF -9L /* mal-formed IFF file. [TBD] Expand this into a * range of error codes.*/ #define LAST_ERROR BAD_IFF /* This MACRO is used to RETURN immediately when a termination condition is * found. This is a pretty weird macro. It requires the caller to declare a * local "IFFP iffp" and assign it. This wouldn't work as a subroutine since * it returns for it's caller. */ #define CheckIFFP() { if (iffp != IFF_OKAY) return(iffp); } /* ---------- ID -------------------------------------------------------*/ typedef LONG ID; /* An ID is four printable ASCII chars but * stored as a LONG for efficient copy & compare.*/ /* Four-character IDentifier builder.*/ #define MakeID(a,b,c,d) ( (LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d) ) /* Standard group IDs. A chunk with one of these IDs contains a SubTypeID followed by zero or more chunks.*/ #define FORM MakeID('F','O','R','M') #define PROP MakeID('P','R','O','P') #define LIST MakeID('L','I','S','T') #define CAT MakeID('C','A','T',' ') #define FILLER MakeID(' ',' ',' ',' ') /* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are reserved * for future standardization.*/ /* Pseudo-ID used internally by chunk reader and writer.*/ #define NULL_CHUNK 0L /* No current chunk.*/ /* ---------- Chunk ----------------------------------------------------*/ /* All chunks start with a type ID and a count of the data bytes that follow--the chunk's "logicl size" or "data size". If that number is odd, a 0 pad byte is written, too. */ typedef struct { ID ckID; LONG ckSize; } ChunkHeader; typedef struct { ID ckID; LONG ckSize; UBYTE ckData[ 1 /*REALLY: ckSize*/ ]; } Chunk; /* Pass ckSize = szNotYetKnown to the writer to mean "compute the size".*/ #define szNotYetKnown 0x80000001L /* Need to know whether a value is odd so can word-align.*/ #define IS_ODD(a) ((a) & 1) /* This macro rounds up to an even number. */ #define WordAlign(size) ((size+1)&~1) /* ALL CHUNKS MUST BE PADDED TO EVEN NUMBER OF BYTES. * ChunkPSize computes the total "physical size" of a padded chunk from * its "data size" or "logical size". */ #define ChunkPSize(dataSize) (WordAlign(dataSize) + sizeof(ChunkHeader)) /* The Grouping chunks (LIST, FORM, PROP, & CAT) contain concatenations of * chunks after a subtype ID that identifies the content chunks. * "FORM type XXXX", "LIST of FORM type XXXX", "PROPerties associated * with FORM type XXXX", or "conCATenation of XXXX".*/ typedef struct { ID ckID; LONG ckSize; /* this ckSize includes "grpSubID".*/ ID grpSubID; } GroupHeader; typedef struct { ID ckID; LONG ckSize; ID grpSubID; UBYTE grpData[ 1 /*REALLY: ckSize-sizeof(grpSubID)*/ ]; } GroupChunk; /* ---------- IFF Reader -----------------------------------------------*/ /******** Routines to support a stream-oriented IFF file reader ******* * * These routines handle lots of details like error checking and skipping * over padding. They're also careful not to read past any containing context. * * These routines ASSUME they're the only ones reading from the file. * Client should check IFFP error codes. Don't press on after an error! * These routines try to have no side effects in the error case, except * partial I/O is sometimes unavoidable. * * All of these routines may return DOS_ERROR. In that case, ask DOS for the * specific error code. * * The overall scheme for the low level chunk reader is to open a "group read * context" with OpenRIFF or OpenRGroup, read the chunks with GetChunkHdr * (and its kin) and IFFReadBytes, and close the context with CloseRGroup. * * The overall scheme for reading an IFF file is to use ReadIFF, ReadIList, * and ReadICat to scan the file. See those procedures, ClientProc (below), * and the skeleton IFF reader. */ /* Client passes ptrs to procedures of this type to ReadIFF which call them * back to handle LISTs, FORMs, CATs, and PROPs. * * Use the GroupContext ptr when calling reader routines like GetChunkHdr. * Look inside the GroupContext ptr for your ClientFrame ptr. You'll * want to type cast it into a ptr to your containing struct to get your * private contextual data (stacked property settings). See below. */ #ifdef FDwAT typedef IFFP ClientProc(struct _GroupContext *); #else typedef IFFP ClientProc(); #endif /* Client's context for reading an IFF file or a group. * Client should actually make this the first component of a larger struct * (it's personal stack "frame") that has a field to store each "interesting" * property encountered. * Either initialize each such field to a global default or keep a boolean * indicating if you've read a property chunk into that field. * Your getList and getForm procs should allocate a new "frame" and copy the * parent frame's contents. The getProp procedure should store into the frame * allocated by getList for the containing LIST. */ typedef struct _ClientFrame { ClientProc *getList, *getProp, *getForm, *getCat; /* client's own data follows; place to stack property settings */ } ClientFrame; /* Our context for reading a group chunk. */ typedef struct _GroupContext { struct _GroupContext *parent; /* Containing group; NULL => whole file. */ ClientFrame *clientFrame; /* Reader data & client's context state. */ BPTR file; /* Byte-stream file handle. */ LONG position; /* The context's logical file position. */ LONG bound; /* File-absolute context bound * or szNotYetKnown (writer only). */ ChunkHeader ckHdr; /* Current chunk header. ckHdr.ckSize = szNotYetKnown * means we need to go back and set the size (writer only). * See also Pseudo-IDs, above. */ ID subtype; /* Group's subtype ID when reading. */ LONG bytesSoFar; /* # bytes read/written of current chunk's data. */ } GroupContext; /* Computes the number of bytes not yet read from the current chunk, given * a group read context gc. */ #define ChunkMoreBytes(gc) ((gc)->ckHdr.ckSize - (gc)->bytesSoFar) /***** Low Level IFF Chunk Reader *****/ #ifdef FDwAT /* Given an open file, open a read context spanning the whole file. * This is normally only called by ReadIFF. * This sets new->clientFrame = clientFrame. * ASSUME context allocated by caller but not initialized. * ASSUME caller doesn't deallocate the context before calling CloseRGroup. * NOT_IFF ERROR if the file is too short for even a chunk header.*/ extern IFFP OpenRIFF(BPTR, GroupContext *, ClientFrame *); /* file, new, clientFrame */ /* Open the remainder of the current chunk as a group read context. * This will be called just after the group's subtype ID has been read * (automatically by GetChunkHdr for LIST, FORM, PROP, and CAT) so the * remainder is a sequence of chunks. * This sets new->clientFrame = parent->clientFrame. The caller should repoint * it at a new clientFrame if opening a LIST context so it'll have a "stack * frame" to store PROPs for the LIST. (It's usually convenient to also * allocate a new Frame when you encounter FORM of the right type.) * * ASSUME new context allocated by caller but not initialized. * ASSUME caller doesn't deallocate the context or access the parent context * before calling CloseRGroup. * BAD_IFF ERROR if context end is odd or extends past parent. */ extern IFFP OpenRGroup(GroupContext *, GroupContext *); /* parent, new */ /* Close a group read context, updating its parent context. * After calling this, the old context may be deallocated and the parent * context can be accessed again. It's okay to call this particular procedure * after an error has occurred reading the group. * This always returns IFF_OKAY. */ extern IFFP CloseRGroup(GroupContext *); /* old */ /* Skip any remaining bytes of the previous chunk and any padding, then * read the next chunk header into context.ckHdr. * If the ckID is LIST, FORM, CAT, or PROP, this automatically reads the * subtype ID into context->subtype. * Caller should dispatch on ckID (and subtype) to an appropriate handler. * * RETURNS context.ckHdr.ckID (the ID of the new chunk header); END_MARK * if there are no more chunks in this context; or NOT_IFF if the top level * file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if malformed chunk, e.g. * ckSize is negative or too big for containing context, ckID isn't positive, * or we hit end-of-file. * * See also GetFChunkHdr, GetF1ChunkHdr, and GetPChunkHdr, below.*/ extern ID GetChunkHdr(GroupContext *); /* context.ckHdr.ckID context */ /* Read nBytes number of data bytes of current chunk. (Use OpenGroup, etc. * instead to read the contents of a group chunk.) You can call this several * times to read the data piecemeal. * CLIENT_ERROR if nBytes < 0. SHORT_CHUNK if nBytes > ChunkMoreBytes(context) * which could be due to a client bug or a chunk that's shorter than it * ought to be (bad form). (on either CLIENT_ERROR or SHORT_CHUNK, * IFFReadBytes won't read any bytes.) */ extern IFFP IFFReadBytes(GroupContext *, BYTE *, LONG); /* context, buffer, nBytes */ /***** IFF File Reader *****/ /* This is a noop ClientProc that you can use for a getList, getForm, getProp, * or getCat procedure that just skips the group. A simple reader might just * implement getForm, store ReadICat in the getCat field of clientFrame, and * use SkipGroup for the getList and getProp procs.*/ extern IFFP SkipGroup(GroupContext *); /* IFF file reader. * Given an open file, allocate a group context and use it to read the FORM, * LIST, or CAT and it's contents. The idea is to parse the file's contents, * and for each FORM, LIST, CAT, or PROP encountered, call the getForm, * getList, getCat, or getProp procedure in clientFrame, passing the * GroupContext ptr. * This is achieved with the aid of ReadIList (which your getList should * call) and ReadICat (which your getCat should call, if you don't just use * ReadICat for your getCat). If you want to handle FORMs, LISTs, and CATs * nested within FORMs, the getForm procedure must dispatch to getForm, * getList, and getCat (it can use GetF1ChunkHdr to make this easy). * * Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a client * proc said "done" first). * See the skeletal getList, getForm, getCat, and getProp procedures. */ extern IFFP ReadIFF(BPTR, ClientFrame *); /* file, clientFrame */ /* IFF LIST reader. * Your "getList" procedure should allocate a ClientFrame, copy the parent's * ClientFrame, and then call this procedure to do all the work. * * Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a client * proc said "done" first). * BAD_IFF ERROR if a PROP appears after a non-PROP. */ extern IFFP ReadIList(GroupContext *, ClientFrame *); /* parent, clientFrame */ /* IFF CAT reader. * Most clients can simply use this to read their CATs. If you must do extra * setup work, put a ptr to your getCat procedure in the clientFrame, and * have that procedure call ReadICat to do the detail work. * * Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a client * proc said "done" first). * BAD_IFF ERROR if a PROP appears in the CAT. */ extern IFFP ReadICat(GroupContext *); /* parent */ /* Call GetFChunkHdr instead of GetChunkHdr to read each chunk inside a FORM. * It just calls GetChunkHdr and returns BAD_IFF if it gets a PROP chunk. */ extern ID GetFChunkHdr(GroupContext *); /* context.ckHdr.ckID context */ /* GetF1ChunkHdr is like GetFChunkHdr, but it automatically dispatches to the * getForm, getList, and getCat procedure (and returns the result) if it * encounters a FORM, LIST, or CAT. */ extern ID GetF1ChunkHdr(GroupContext *); /* context.ckHdr.ckID context */ /* Call GetPChunkHdr instead of GetChunkHdr to read each chunk inside a PROP. * It just calls GetChunkHdr and returns BAD_IFF if it gets a group chunk. */ extern ID GetPChunkHdr(GroupContext *); /* context.ckHdr.ckID context */ #else /* not FDwAT */ extern IFFP OpenRIFF(); extern IFFP OpenRGroup(); extern IFFP CloseRGroup(); extern ID GetChunkHdr(); extern IFFP IFFReadBytes(); extern IFFP SkipGroup(); extern IFFP ReadIFF(); extern IFFP ReadIList(); extern IFFP ReadICat(); extern ID GetFChunkHdr(); extern ID GetF1ChunkHdr(); extern ID GetPChunkHdr(); #endif /* not FDwAT */ /* ---------- IFF Writer -----------------------------------------------*/ /******* Routines to support a stream-oriented IFF file writer ******* * * These routines will random access back to set a chunk size value when the * caller doesn't know it ahead of time. They'll also do things automatically * like padding and error checking. * * These routines ASSUME they're the only ones writing to the file. * Client should check IFFP error codes. Don't press on after an error! * These routines try to have no side effects in the error case, except that * partial I/O is sometimes unavoidable. * * All of these routines may return DOS_ERROR. In that case, ask DOS for the * specific error code. * * The overall scheme is to open an output GroupContext via OpenWIFF or * OpenWGroup, call either PutCk or {PutCkHdr {IFFWriteBytes}* PutCkEnd} for * each chunk, then use CloseWGroup to close the GroupContext. * * To write a group (LIST, FORM, PROP, or CAT), call StartWGroup, write out * its chunks, then call EndWGroup. StartWGroup automatically writes the * group header and opens a nested context for writing the contents. * EndWGroup closes the nested context and completes the group chunk. */ #ifdef FDwAT /* Given a file open for output, open a write context. * The "limit" arg imposes a fence or upper limit on the logical file * position for writing data in this context. Pass in szNotYetKnown to be * bounded only by disk capacity. * ASSUME new context structure allocated by caller but not initialized. * ASSUME caller doesn't deallocate the context before calling CloseWGroup. * The caller is only allowed to write out one FORM, LIST, or CAT in this top * level context (see StartWGroup and PutCkHdr). * CLIENT_ERROR if limit is odd.*/ extern IFFP OpenWIFF(BPTR, GroupContext *, LONG); /* file, new, limit {file position} */ /* Start writing a group (presumably LIST, FORM, PROP, or CAT), opening a * nested context. The groupSize includes all nested chunks + the subtype ID. * * The subtype of a LIST or CAT is a hint at the contents' FORM type(s). Pass * in FILLER if it's a mixture of different kinds. * * This writes the chunk header via PutCkHdr, writes the subtype ID via * IFFWriteBytes, and calls OpenWGroup. The caller may then write the nested * chunks and finish by calling EndWGroup. * The OpenWGroup call sets new->clientFrame = parent->clientFrame. * * ASSUME new context structure allocated by caller but not initialized. * ASSUME caller doesn't deallocate the context or access the parent context * before calling CloseWGroup. * ERROR conditions: See PutCkHdr, IFFWriteBytes, OpenWGroup. */ extern IFFP StartWGroup(GroupContext *, ID, LONG, ID, GroupContext *); /* parent, groupType, groupSize, subtype, new */ /* End a group started by StartWGroup. * This just calls CloseWGroup and PutCkEnd. * ERROR conditions: See CloseWGroup and PutCkEnd. */ extern IFFP EndWGroup(GroupContext *); /* old */ /* Open the remainder of the current chunk as a group write context. * This is normally only called by StartWGroup. * * Any fixed limit to this group chunk or a containing context will impose * a limit on the new context. * This will be called just after the group's subtype ID has been written * so the remaining contents will be a sequence of chunks. * This sets new->clientFrame = parent->clientFrame. * ASSUME new context structure allocated by caller but not initialized. * ASSUME caller doesn't deallocate the context or access the parent context * before calling CloseWGroup. * CLIENT_ERROR if context end is odd or PutCkHdr wasn't called first. */ extern IFFP OpenWGroup(GroupContext *, GroupContext *); /* parent, new */ /* Close a write context and update its parent context. * This is normally only called by EndWGroup. * * If this is a top level context (created by OpenWIFF) we'll set the file's * EOF (end of file) but won't close the file. * After calling this, the old context may be deallocated and the parent * context can be accessed again. * * Amiga DOS Note: There's no call to set the EOF. We just position to the * desired end and return. Caller must Close file at that position. * CLIENT_ERROR if PutCkEnd wasn't called first. */ extern IFFP CloseWGroup(GroupContext *); /* old */ /* Write a whole chunk to a GroupContext. This writes a chunk header, ckSize * data bytes, and (if needed) a pad byte. It also updates the GroupContext. * CLIENT_ERROR if ckSize == szNotYetKnown. See also PutCkHdr errors. */ extern IFFP PutCk(GroupContext *, ID, LONG, BYTE *); /* context, ckID, ckSize, *data */ /* Write just a chunk header. Follow this will any number of calls to * IFFWriteBytes and finish with PutCkEnd. * If you don't yet know how big the chunk is, pass in ckSize = szNotYetKnown, * then PutCkEnd will set the ckSize for you later. * Otherwise, IFFWriteBytes and PutCkEnd will ensure that the specified * number of bytes get written. * CLIENT_ERROR if the chunk would overflow the GroupContext's bound, if * PutCkHdr was previously called without a matching PutCkEnd, if ckSize < 0 * (except szNotYetKnown), if you're trying to write something other * than one FORM, LIST, or CAT in a top level (file level) context, or * if ckID <= 0 (these illegal ID values are used for error codes). */ extern IFFP PutCkHdr(GroupContext *, ID, LONG); /* context, ckID, ckSize */ /* Write nBytes number of data bytes for the current chunk and update * GroupContext. * CLIENT_ERROR if this would overflow the GroupContext's limit or the * current chunk's ckSize, or if PutCkHdr wasn't called first, or if * nBytes < 0. */ extern IFFP IFFWriteBytes(GroupContext *, BYTE *, LONG); /* context, *data, nBytes */ /* Complete the current chunk, write a pad byte if needed, and update * GroupContext. * If current chunk's ckSize = szNotYetKnown, this goes back and sets the * ckSize in the file. * CLIENT_ERROR if PutCkHdr wasn't called first, or if client hasn't * written 'ckSize' number of bytes with IFFWriteBytes. */ extern IFFP PutCkEnd(GroupContext *); /* context */ #else /* not FDwAT */ extern IFFP OpenWIFF(); extern IFFP StartWGroup(); extern IFFP EndWGroup(); extern IFFP OpenWGroup(); extern IFFP CloseWGroup(); extern IFFP PutCk(); extern IFFP PutCkHdr(); extern IFFP IFFWriteBytes(); extern IFFP PutCkEnd(); #endif /* not FDwAT */ #endif IFF_H STUNKYFLUFF set `sum iff.h` if test 16961 != $1 then echo iff.h: Checksum error. Is: $1, should be: 16961. fi # # echo x - ilbm.h: cat >ilbm.h <<\STUNKYFLUFF #ifndef ILBM_H #define ILBM_H /*----------------------------------------------------------------------* * ILBM.H Definitions for InterLeaved BitMap raster image. 1/23/86 * * By Jerry Morrison and Steve Shaw, Electronic Arts. * This software is in the public domain. * * This version for the Commodore-Amiga computer. *----------------------------------------------------------------------*/ #ifndef COMPILER_H #include "iff/compiler.h" #endif #ifndef GRAPHICS_GFX_H #include "graphics/gfx.h" #endif #include "iff/iff.h" #define ID_ILBM MakeID('I','L','B','M') #define ID_BMHD MakeID('B','M','H','D') #define ID_CMAP MakeID('C','M','A','P') #define ID_GRAB MakeID('G','R','A','B') #define ID_DEST MakeID('D','E','S','T') #define ID_SPRT MakeID('S','P','R','T') #define ID_CAMG MakeID('C','A','M','G') #define ID_BODY MakeID('B','O','D','Y') /* ---------- BitMapHeader ---------------------------------------------*/ typedef UBYTE Masking; /* Choice of masking technique.*/ #define mskNone 0 #define mskHasMask 1 #define mskHasTransparentColor 2 #define mskLasso 3 typedef UBYTE Compression; /* Choice of compression algorithm applied to * each row of the source and mask planes. "cmpByteRun1" is the byte run * encoding generated by Mac's PackBits. See Packer.h . */ #define cmpNone 0 #define cmpByteRun1 1 /* Aspect ratios: The proper fraction xAspect/yAspect represents the pixel * aspect ratio pixel_width/pixel_height. * * For the 4 Amiga display modes: * 320 x 200: 10/11 (these pixels are taller than they are wide) * 320 x 400: 20/11 * 640 x 200: 5/11 * 640 x 400: 10/11 */ #define x320x200Aspect 10 #define y320x200Aspect 11 #define x320x400Aspect 20 #define y320x400Aspect 11 #define x640x200Aspect 5 #define y640x200Aspect 11 #define x640x400Aspect 10 #define y640x400Aspect 11 /* A BitMapHeader is stored in a BMHD chunk. */ typedef struct { UWORD w, h; /* raster width & height in pixels */ WORD x, y; /* position for this image */ UBYTE nPlanes; /* # source bitplanes */ Masking masking; /* masking technique */ Compression compression; /* compression algoithm */ UBYTE pad1; /* UNUSED. For consistency, put 0 here.*/ UWORD transparentColor; /* transparent "color number" */ UBYTE xAspect, yAspect; /* aspect ratio, a rational number x/y */ WORD pageWidth, pageHeight; /* source "page" size in pixels */ } BitMapHeader; /* RowBytes computes the number of bytes in a row, from the width in pixels.*/ #define RowBytes(w) (((w) + 15) >> 4 << 1) /* ---------- ColorRegister --------------------------------------------*/ /* A CMAP chunk is a packed array of ColorRegisters (3 bytes each). */ typedef struct { UBYTE red, green, blue; /* MUST be UBYTEs so ">> 4" won't sign extend.*/ } ColorRegister; /* Use this constant instead of sizeof(ColorRegister). */ #define sizeofColorRegister 3 typedef WORD Color4; /* Amiga RAM version of a color-register, * with 4 bits each RGB in low 12 bits.*/ /* Maximum number of bitplanes in RAM. Current Amiga max w/dual playfield. */ #define MaxAmDepth 6 /* ---------- Point2D --------------------------------------------------*/ /* A Point2D is stored in a GRAB chunk. */ typedef struct { WORD x, y; /* coordinates (pixels) */ } Point2D; /* ---------- DestMerge ------------------------------------------------*/ /* A DestMerge is stored in a DEST chunk. */ typedef struct { UBYTE depth; /* # bitplanes in the original source */ UBYTE pad1; /* UNUSED; for consistency store 0 here */ UWORD planePick; /* how to scatter source bitplanes into destination */ UWORD planeOnOff; /* default bitplane data for planePick */ UWORD planeMask; /* selects which bitplanes to store into */ } DestMerge; /* ---------- SpritePrecedence -----------------------------------------*/ /* A SpritePrecedence is stored in a SPRT chunk. */ typedef UWORD SpritePrecedence; /* ---------- Viewport Mode --------------------------------------------*/ /* A Commodore Amiga ViewPort->Modes is stored in a CAMG chunk. */ /* The chunk's content is declared as a LONG. */ /* ---------- CRange ---------------------------------------------------*/ /* A CRange is store in a CRNG chunk. */ typedef struct { WORD pad1; /* reserved for future use; store 0 here */ WORD rate; /* color cycling rate, 16384 = 60 steps/second */ WORD active; /* nonzero means color cycling is turned on */ UBYTE low, high; /* lower and upper color registers selected */ } CRange; /* ---------- ILBM Writer Support Routines -----------------------------*/ /* Note: Just call PutCk to write a BMHD, GRAB, DEST, SPRT, or CAMG * chunk. As below. */ #define PutBMHD(context, bmHdr) \ PutCk(context, ID_BMHD, sizeof(BitMapHeader), (BYTE *)bmHdr) #define PutGRAB(context, point2D) \ PutCk(context, ID_GRAB, sizeof(Point2D), (BYTE *)point2D) #define PutDEST(context, destMerge) \ PutCk(context, ID_DEST, sizeof(DestMerge), (BYTE *)destMerge) #define PutSPRT(context, spritePrec) \ PutCk(context, ID_SPRT, sizeof(SpritePrecedence), (BYTE *)spritePrec) #ifdef FDwAT /* Initialize a BitMapHeader record for a full-BitMap ILBM picture. * This gets w, h, and nPlanes from the BitMap fields BytesPerRow, Rows, and * Depth. It assumes you want w = bitmap->BytesPerRow * 8 . * CLIENT_ERROR if bitmap->BytesPerRow isn't even, as required by ILBM format. * * If (pageWidth, pageHeight) is (320, 200), (320, 400), (640, 200), or * (640, 400) this sets (xAspect, yAspect) based on those 4 Amiga display * modes. Otherwise, it sets them to (1, 1). * * After calling this, store directly into the BitMapHeader if you want to * override any settings, e.g. to make nPlanes smaller, to reduce w a little, * or to set a position (x, y) other than (0, 0).*/ extern IFFP InitBMHdr(BitMapHeader *, struct BitMap *, /* bmHdr, bitmap */ int, int, int, WORD, WORD); /* masking, compression, transparentColor, pageWidth, pageHeight */ /* Masking, Compression, UWORD -- are the desired types, but get * compiler warnings if use them. */ /* Output a CMAP chunk to an open FORM ILBM write context. */ extern IFFP PutCMAP(GroupContext *, WORD *, UBYTE); /* context, colorMap, depth */ /* This procedure outputs a BitMap as an ILBM's BODY chunk with * bitplane and mask data. Compressed if bmHdr->compression == cmpByteRun1. * If the "mask" argument isn't NULL, it merges in the mask plane, too. * (A fancier routine could write a rectangular portion of an image.) * This gets Planes (bitplane ptrs) from "bitmap". * * CLIENT_ERROR if bitmap->Rows != bmHdr->h, or if * bitmap->BytesPerRow != RowBytes(bmHdr->w), or if * bitmap->Depth < bmHdr->nPlanes, or if bmHdr->nPlanes > MaxAmDepth, or if * bufsize < MaxPackedSize(bitmap->BytesPerRow), or if * bmHdr->compression > cmpByteRun1. */ extern IFFP PutBODY( GroupContext *, struct BitMap *, BYTE *, BitMapHeader *, BYTE *, LONG); /* context, bitmap, mask, bmHdr, buffer, bufsize */ #else /*not FDwAT*/ extern IFFP InitBMHdr(); extern IFFP PutCMAP(); extern IFFP PutBODY(); #endif FDwAT /* ---------- ILBM Reader Support Routines -----------------------------*/ /* Note: Just call IFFReadBytes to read a BMHD, GRAB, DEST, SPRT, or CAMG * chunk. As below. */ #define GetBMHD(context, bmHdr) \ IFFReadBytes(context, (BYTE *)bmHdr, sizeof(BitMapHeader)) #define GetGRAB(context, point2D) \ IFFReadBytes(context, (BYTE *)point2D, sizeof(Point2D)) #define GetDEST(context, destMerge) \ IFFReadBytes(context, (BYTE *)destMerge, sizeof(DestMerge)) #define GetSPRT(context, spritePrec) \ IFFReadBytes(context, (BYTE *)spritePrec, sizeof(SpritePrecedence)) /* GetBODY can handle a file with up to 16 planes plus a mask.*/ #define MaxSrcPlanes 16+1 #ifdef FDwAT /* Input a CMAP chunk from an open FORM ILBM read context. * This converts to an Amiga color map: 4 bits each of red, green, blue packed * into a 16 bit color register. * pNColorRegs is passed in as a pointer to a UBYTE variable that holds * the number of ColorRegisters the caller has space to hold. GetCMAP sets * that variable to the number of color registers actually read.*/ extern IFFP GetCMAP(GroupContext *, WORD *, UBYTE *); /* context, colorMap, pNColorRegs */ /* GetBODY reads an ILBM's BODY into a client's bitmap, de-interleaving and * decompressing. * * Caller should first compare bmHdr dimensions (rowWords, h, nPlanes) with * bitmap dimensions, and consider reallocating the bitmap. * If file has more bitplanes than bitmap, this reads first few planes (low * order ones). If bitmap has more bitplanes, the last few are untouched. * This reads the MIN(bmHdr->h, bitmap->Rows) rows, discarding the bottom * part of the source or leaving the bottom part of the bitmap untouched. * * GetBODY returns CLIENT_ERROR if asked to perform a conversion it doesn't * handle. It only understands compression algorithms cmpNone and cmpByteRun1. * The filed row width (# words) must agree with bitmap->BytesPerRow. * * Caller should use bmHdr.w; GetBODY only uses it to compute the row width * in words. Pixels to the right of bmHdr.w are not defined. * * [TBD] In the future, GetBODY could clip the stored image horizontally or * fill (with transparentColor) untouched parts of the destination bitmap. * * GetBODY stores the mask plane, if any, in the buffer pointed to by mask. * If mask == NULL, GetBODY will skip any mask plane. If * (bmHdr.masking != mskHasMask) GetBODY just leaves the caller's mask alone. * * GetBODY needs a buffer large enough for two compressed rows. * It returns CLIENT_ERROR if bufsize < 2 * MaxPackedSize(bmHdr.rowWords * 2). * * GetBODY can handle a file with up to MaxSrcPlanes planes. It returns * CLIENT_ERROR if the file has more. (Could be due to a bum file, though.) * If GetBODY fails, itt might've modified the client's bitmap. Sorry.*/ extern IFFP GetBODY( GroupContext *, struct BitMap *, BYTE *, BitMapHeader *, BYTE *, LONG); /* context, bitmap, mask, bmHdr, buffer, bufsize */ /* [TBD] Add routine(s) to create masks when reading ILBMs whose * masking != mskHasMask. For mskNone, create a rectangular mask. For * mskHasTransparentColor, create a mask from transparentColor. For mskLasso, * create an "auto mask" by filling transparent color from the edges. */ #else /*not FDwAT*/ extern IFFP GetCMAP(); extern IFFP GetBODY(); #endif FDwAT #endif ILBM_H STUNKYFLUFF set `sum ilbm.h` if test 64527 != $1 then echo ilbm.h: Checksum error. Is: $1, should be: 64527. fi # # echo x - intuall.h: cat >intuall.h <<\STUNKYFLUFF /*** intuall.h **********************************************************/ /* intuall.h, Include lots of Amiga-provided header files. 1/22/86 */ /* Plus the portability file "iff/compiler.h" which should be tailored */ /* for your compiler. */ /* */ /* By Jerry Morrison and Steve Shaw, Electronic Arts. */ /* This software is in the public domain. */ /* */ /* This version for the Commodore-Amiga computer. */ /* */ /************************************************************************/ #include "iff/compiler.h" /* COMPILER-DEPENDENCIES */ /* Dummy definitions because some includes below are commented out. * This avoids 'undefined structure' warnings when compile. * This is safe as long as only use POINTERS to these structures. */ struct Region { int dummy; }; struct VSprite { int dummy; }; struct collTable { int dummy; }; struct CopList { int dummy; }; struct UCopList { int dummy; }; struct cprlist { int dummy; }; struct copinit { int dummy; }; struct TimeVal { int dummy; }; #include "exec/types.h" #include "exec/nodes.h" #include "exec/lists.h" #include "exec/libraries.h" #include "exec/ports.h" #include "exec/tasks.h" #include "exec/devices.h" #include "exec/interrupts.h" #include "exec/io.h" #include "exec/memory.h" #include "exec/alerts.h" /* ALWAYS INCLUDE GFX.H before any other amiga includes */ #include "graphics/gfx.h" /*#include "hardware/blit.h"*/ /***** #include "graphics/collide.h" #include "graphics/copper.h" #include "graphics/display.h" #include "hardware/dmabits.h" #include "graphics/gels.h" ***/ #include "graphics/clip.h" #include "graphics/rastport.h" #include "graphics/view.h" #include "graphics/gfxbase.h" /*#include "hardware/intbits.h"*/ #include "graphics/gfxmacros.h" #include "graphics/layers.h" #include "graphics/text.h" #include "graphics/sprite.h" /*#include "hardware/custom.h"*/ /*#include "libraries/dos.h"*/ /*#include "libraries/dosextens.h"*/ #include "devices/timer.h" #include "devices/inputevent.h" #include "devices/keymap.h" #include "intuition/intuition.h" /*#include "intuitionbase.h"*/ /*#include "intuinternal.h"*/ STUNKYFLUFF set `sum intuall.h` if test 01286 != $1 then echo intuall.h: Checksum error. Is: $1, should be: 01286. fi # # echo x - packer.h: cat >packer.h <<\STUNKYFLUFF #ifndef PACKER_H #define PACKER_H /*----------------------------------------------------------------------* * PACKER.H typedefs for Data-Compresser. 1/22/86 * * This module implements the run compression algorithm "cmpByteRun1"; the * same encoding generated by Mac's PackBits. * * By Jerry Morrison and Steve Shaw, Electronic Arts. * This software is in the public domain. * * This version for the Commodore-Amiga computer. *----------------------------------------------------------------------*/ #ifndef COMPILER_H #include "iff/compiler.h" #endif /* This macro computes the worst case packed size of a "row" of bytes. */ #define MaxPackedSize(rowSize) ( (rowSize) + ( ((rowSize)+127) >> 7 ) ) #ifdef FDwAT /* Compiler handles Function Declaration with Argument Types */ /* Given POINTERS to POINTER variables, packs one row, updating the source * and destination pointers. Returns the size in bytes of the packed row. * ASSUMES destination buffer is large enough for the packed row. * See MaxPackedSize. */ extern LONG PackRow(BYTE **, BYTE **, LONG); /* pSource, pDest, rowSize */ /* Given POINTERS to POINTER variables, unpacks one row, updating the source * and destination pointers until it produces dstBytes bytes (i.e., the * rowSize that went into PackRow). * If it would exceed the source's limit srcBytes or if a run would overrun * the destination buffer size dstBytes, it stops and returns TRUE. * Otherwise, it returns FALSE (no error). */ extern BOOL UnPackRow(BYTE **, BYTE **, WORD, WORD); /* pSource, pDest, srcBytes, dstBytes */ #else /* not FDwAT */ extern LONG PackRow(); extern BOOL UnPackRow(); #endif /* FDwAT */ #endif STUNKYFLUFF set `sum packer.h` if test 55164 != $1 then echo packer.h: Checksum error. Is: $1, should be: 55164. fi # # echo x - putpict.h: cat >putpict.h <<\STUNKYFLUFF #ifndef PUTPICT_H #define PUTPICT_H /** putpict.h ********************************************************* */ /* PutPict(). Given a BitMap and a color map in RAM on the Amiga, */ /* outputs as an ILBM. See /iff/ilbm.h & /iff/ilbmw.c. 23-Jan-86 */ /* */ /* By Jerry Morrison and Steve Shaw, Electronic Arts. */ /* This software is in the public domain. */ /* */ /* This version for the Commodore-Amiga computer. */ /* */ /************************************************************************/ #ifndef COMPILER_H #include "iff/compiler.h" #endif #ifndef ILBM_H #include "iff/ilbm.h" #endif #ifdef FDwAT /****** IffErr *************************************************************/ /* Returns the iff error code and resets it to zero */ /***************************************************************************/ extern IFFP IffErr(void); /****** PutPict ************************************************************/ /* Put a picture into an IFF file */ /* Pass in mask == NULL for no mask. */ /* */ /* Buffer should be big enough for one packed scan line */ /* Buffer used as temporary storage to speed-up writing. */ /* A large buffer, say 8KB, is useful for minimizing Write and Seek calls. */ /* (See /iff/gio.h & /iff/gio.c). */ /***************************************************************************/ extern BOOL PutPict(LONG, struct BitMap *, WORD,WORD, WORD *, BYTE *, LONG); /* file, bm, pageW,pageH,colorMap, buffer,bufsize */ #else /*not FDwAT*/ extern IFFP IffErr(); extern BOOL PutPict(); #endif FDwAT #endif PUTPICT_H STUNKYFLUFF set `sum putpict.h` if test 55308 != $1 then echo putpict.h: Checksum error. Is: $1, should be: 55308. fi # # echo x - readpict.h: cat >readpict.h <<\STUNKYFLUFF #ifndef READPICT_H #define READPICT_H /** ReadPict.h **************************************************************/ /* */ /* Read an ILBM raster image file into RAM. 1/23/86. */ /* */ /* By Jerry Morrison, Steve Shaw, and Steve Hayes, Electronic Arts. */ /* This software is in the public domain. */ /* */ /* USE THIS AS AN EXAMPLE PROGRAM FOR AN IFF READER. */ /* */ /* The IFF reader portion is essentially a recursive-descent parser. */ /****************************************************************************/ /* ILBMFrame is our "client frame" for reading FORMs ILBM in an IFF file. * We allocate one of these on the stack for every LIST or FORM encountered * in the file and use it to hold BMHD & CMAP properties. We also allocate * an initial one for the whole file. */ typedef struct { ClientFrame clientFrame; UBYTE foundBMHD; UBYTE nColorRegs; BitMapHeader bmHdr; Color4 colorMap[32 /*1<<MaxAmDepth*/ ]; /* If you want to read any other property chunks, e.g. GRAB or CAMG, add * fields to this record to store them. */ } ILBMFrame; /** ReadPicture() *********************************************************** * * Read a picture from an IFF file, given a file handle open for reading. * Allocates BitMap RAM by calling (*Allocator)(size). * ****************************************************************************/ typedef UBYTE *UBytePtr; #ifdef FDwAT typedef UBytePtr Allocator(LONG); /* Allocator: a memory allocation procedure which only requires a size * argument. (No Amiga memory flags argument.) */ extern IFFP ReadPicture(LONG, struct BitMap *, ILBMFrame *, Allocator *); /* file, bm, iFrame, allocator */ /* iFrame is the top level "client frame". */ /* allocator is a ptr to your allocation procedure. It must always * allocate in Chip memory (for bitmap data). */ /* PS: Notice how we used two "typedef"s above to make allocator's type * meaningful to humans. * Consider the usual C style: UBYTE *(*)(), or is it (UBYTE *)(*()) ? */ #else /* not FDwAT */ typedef UBytePtr Allocator(); extern IFFP ReadPicture(); #endif #endif READPICT_H STUNKYFLUFF set `sum readpict.h` if test 28263 != $1 then echo readpict.h: Checksum error. Is: $1, should be: 28263. fi # # echo x - remalloc.h: cat >remalloc.h <<\STUNKYFLUFF /** RemAlloc.h **********************************************************/ /* ChipAlloc(), ExtAlloc(), RemAlloc(), RemFree(). */ /* ALLOCators which REMember the size allocated, for simpler freeing. */ /* */ /* Date Who Changes */ /* --------- --- -------------------------------------------------------*/ /* 16-Jan-86 sss Created from DPaint/DAlloc.c */ /* 22-Jan-86 jhm Include Compiler.h */ /* 25-Jan-86 sss Added ChipNoClearAlloc,ExtNoClearAlloc */ /* */ /* By Jerry Morrison and Steve Shaw, Electronic Arts. */ /* This software is in the public domain. */ /* */ /* This version for the Commodore-Amiga computer. */ /* */ /************************************************************************/ #ifndef REM_ALLOC_H #define REM_ALLOC_H #ifndef COMPILER_H #include "iff/compiler.h" #endif /* How these allocators work: * The allocator procedures get the memory from the system allocator, * actually allocating 4 extra bytes. We store the length of the node in * the first 4 bytes then return a ptr to the rest of the storage. The * deallocator can then find the node size and free it. */ #ifdef FDwAT /* RemAlloc allocates a node with "size" bytes of user data. * Example: * struct BitMap *bm; * bm = (struct BitMap *)RemAlloc( sizeof(struct BitMap), ...flags... ); */ extern UBYTE *RemAlloc(LONG, LONG); /* size, flags */ /* ALLOCator that remembers size, allocates in CHIP-accessable memory. * Use for all data to be displayed on screen, all sound data, all data to be * blitted, disk buffers, or access by any other DMA channel. * Does clear memory being allocated.*/ extern UBYTE *ChipAlloc(LONG); /* size */ /* ChipAlloc, without clearing memory. Purpose: speed when allocate * large area that will be overwritten anyway.*/ extern UBYTE *ChipNoClearAlloc(LONG); /* ALLOCator that remembers size, allocates in extended memory. * Does clear memory being allocated. * NOTICE: does NOT declare "MEMF_FAST". This allows machines * lacking extended memory to allocate within chip memory, * assuming there is enough memory left.*/ extern UBYTE *ExtAlloc(LONG); /* size */ /* ExtAlloc, without clearing memory. Purpose: speed when allocate * large area that will be overwritten anyway.*/ extern UBYTE *ExtNoClearAlloc(LONG); /* FREEs either chip or extended memory, if allocated with an allocator * which REMembers size allocated. * Safe: won't attempt to de-allocate a NULL pointer. * Returns NULL so caller can do * p = RemFree(p); */ extern UBYTE *RemFree(UBYTE *); /* p */ #else /* not FDwAT */ extern UBYTE *RemAlloc(); extern UBYTE *ChipAlloc(); extern UBYTE *ExtAlloc(); extern UBYTE *RemFree(); #endif /* FDwAT */ #endif REM_ALLOC_H STUNKYFLUFF set `sum remalloc.h` if test 47940 != $1 then echo remalloc.h: Checksum error. Is: $1, should be: 47940. fi exit 0